home *** CD-ROM | disk | FTP | other *** search
/ Aminet 43 / Aminet 43 (2001)(GTI - Schatztruhe)[!][Jun 2001].iso / Aminet / comm / mail / YAM22src.lha / YAM_WR.c < prev    next >
C/C++ Source or Header  |  2000-11-03  |  99KB  |  2,142 lines

  1. /***************************************************************************
  2.  
  3.  YAM - Yet Another Mailer
  4.  Copyright (C) 2000  Marcel Beck <mbeck@yam.ch>
  5.  
  6.  This program is free software; you can redistribute it and/or modify
  7.  it under the terms of the GNU General Public License as published by
  8.  the Free Software Foundation; either version 2 of the License, or
  9.  (at your option) any later version.
  10.  
  11.  This program is distributed in the hope that it will be useful,
  12.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  GNU General Public License for more details.
  15.  
  16.  You should have received a copy of the GNU General Public License
  17.  along with this program; if not, write to the Free Software
  18.  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  
  20.  YAM Official Support Site :  http://www.yam.ch
  21.  YAM OpenSource project    :  http://sourceforge.net/projects/yamos/
  22.  
  23. ***************************************************************************/
  24.  
  25. #include "YAM.h"
  26.  
  27. /***************************************************************************
  28.  Module: Write
  29. ***************************************************************************/
  30.  
  31. /*** Translate aliases ***/
  32. /// WR_ResolveName
  33. //  Looks for an alias, email address or name in the address book
  34. char FailedAlias[SIZE_NAME];
  35. int WR_ResolveName(int winnum, char *name, char **adrstr, BOOL nolists)
  36. {
  37.    int hits = 0, i, retcode;
  38.    char *p;
  39.    struct ABEntry *ab;
  40.    struct MUIS_Listtree_TreeNode *tn, *tn2;
  41.    struct Person pe;
  42.  
  43.    ExtractAddress(name, &pe);
  44.    if (pe.Address[0]) if (p = strchr(pe.Address, '@')) // is it an address?
  45.    {
  46.       if (!p[1]) strcpy(p, strchr(C->EmailAddress, '@'));
  47.       if (**adrstr) *adrstr = StrBufCat(*adrstr, ", ");
  48.       *adrstr = StrBufCat(*adrstr, BuildAddrName2(&pe));
  49.       return 0; // no error or warning
  50.    }
  51.    pe.Address[0] = 0;
  52.    stccpy(FailedAlias, name, SIZE_NAME);
  53.    AB_SearchEntry(MUIV_Lt_GetEntry_ListNode_Root, name, ASM_ALIAS|ASM_USER|ASM_LIST|ASM_GROUP, &hits, &tn);
  54.    if (hits > 1) return 3; // multiple matches
  55.    if (!hits)
  56.    {
  57.       AB_SearchEntry(MUIV_Lt_GetEntry_ListNode_Root, name, ASM_REALNAME|ASM_USER|ASM_LIST|ASM_GROUP, &hits, &tn);
  58.       if (hits > 1) return 3; else if (!hits) return 2;
  59.    }
  60.    ab = tn->tn_User;
  61.    switch (ab->Type)
  62.    {
  63.       case AET_USER:
  64.          if (**adrstr) *adrstr = StrBufCat(*adrstr, ", ");
  65.          *adrstr = StrBufCat(*adrstr, BuildAddrName(ab->Address, ab->RealName));
  66.          break;
  67.       case AET_LIST:
  68.          if (nolists) return 4;
  69.          if (winnum >= 0) if ((ab->Address[0] || ab->RealName[0]) && !G->WR[winnum]->ListEntry) G->WR[winnum]->ListEntry = ab;
  70.          if (ab->Members)
  71.          {
  72.             char *ptr;
  73.             for (ptr = ab->Members; *ptr; ptr++)
  74.             {
  75.                char *nptr = strchr(ptr, '\n');
  76.                if (nptr) *nptr = 0; else break;
  77.                retcode = WR_ResolveName(winnum, ptr, adrstr, nolists);
  78.                *nptr = '\n'; ptr = nptr;
  79.                if (retcode) return retcode;
  80.             }
  81.          }
  82.          break;
  83.       case AET_GROUP:
  84.          if (nolists) return 4;
  85.          for (i=0; ; i++)
  86.             if (tn2 = (struct MUIS_Listtree_TreeNode *)DoMethod(G->AB->GUI.LV_ADRESSES, MUIM_Listtree_GetEntry, tn, i, MUIV_Lt_GetEntry_Flags_SameLevel))
  87.             {
  88.                struct ABEntry *ab2 = tn2->tn_User;
  89.                if (retcode = WR_ResolveName(winnum, ab2->Alias, adrstr, nolists)) return retcode;
  90.             }
  91.             else break;
  92.          break;
  93.    }
  94.    return 0;
  95. }
  96. ///
  97. /// WR_ExpandAddresses
  98. //  Expands aliases and names in a recipient field to valid e-mail addresses
  99. char *WR_ExpandAddresses(int winnum, char *src, BOOL quiet, BOOL single)
  100. {
  101.    char *source, *buffer = malloc(strlen(src)+1), *next, *adr = AllocStrBuf(SIZE_DEFAULT);
  102.    int err;
  103.  
  104.    strcpy(source = buffer, src);
  105.    while (source)
  106.    {
  107.       if (!*source) break;
  108.       if (next = MyStrChr(source, ',')) *next++ = 0;
  109.       if (err = WR_ResolveName(winnum, Trim(source), &adr, single))
  110.       {
  111.          if (err == 2 && !quiet) ER_NewError(GetStr(MSG_ER_AliasNotFound), FailedAlias, NULL);
  112.          if (err == 3 && !quiet) ER_NewError(GetStr(MSG_ER_AmbiguousAlias), FailedAlias, NULL);
  113.          if (err == 4 && !quiet) ER_NewError(GetStr(MSG_ER_InvalidAlias), FailedAlias, NULL);
  114.          FreeStrBuf(adr); adr = NULL;
  115.          break;
  116.       }
  117.       if (single) break;
  118.       source = next;
  119.    }
  120.    free(buffer);
  121.    return adr;
  122. }
  123. ///
  124. /// WR_VerifyAutoFunc
  125. //  Checks recipient field (user pressed return key)
  126. SAVEDS ASM void WR_VerifyAutoFunc(REG(a1) int *arg)
  127. {
  128.    APTR str = (APTR)arg[0], next = str;
  129.    char *value, *adr;
  130.    get(str, MUIA_String_Contents, &value);
  131.    if (adr = WR_ExpandAddresses(arg[1], value, TRUE, arg[2]))
  132.    {
  133.       FreeStrBuf(adr);
  134.       get(str, MUIA_UserData, &next);
  135.    }
  136.    else DisplayBeep(0);
  137.    if (next) set(_win(next), MUIA_Window_ActiveObject, next);
  138. }
  139. MakeHook(WR_VerifyAutoHook, WR_VerifyAutoFunc);
  140. ///
  141. /// WR_VerifyManualFunc
  142. //  Checks and expands recipient field (user clicked gadget)
  143. SAVEDS ASM void WR_VerifyManualFunc(REG(a1) int *arg)
  144. {
  145.    APTR object = (APTR)arg[0];
  146.    char *value, *adr;
  147.    get(object, MUIA_String_Contents, &value);
  148.    if (adr = WR_ExpandAddresses(arg[1], value, FALSE, arg[2]))
  149.    {
  150.       setstring(object, adr);
  151.       FreeStrBuf(adr);
  152.    }
  153. }
  154. MakeHook(WR_VerifyManualHook, WR_VerifyManualFunc);
  155. ///
  156.  
  157. /*** Attachments list ***/
  158. /// WR_GetFileEntry
  159. //  Fills form with data from selected list entry
  160. SAVEDS ASM void WR_GetFileEntry(REG(a1) int *arg)
  161. {
  162.    int winnum = *arg;
  163.    struct Attach *attach = NULL;
  164.    struct WR_GUIData *gui = &G->WR[winnum]->GUI;
  165.  
  166.    DoMethod(gui->LV_ATTACH, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &attach);
  167.    DoMethod(G->App, MUIM_MultiSet, MUIA_Disabled, attach ? FALSE : TRUE, gui->RA_ENCODING, gui->ST_CTYPE, gui->ST_DESC, gui->BT_DEL, gui->BT_DISPLAY, NULL);
  168.    if (attach)
  169.    {
  170.       nnset(gui->RA_ENCODING, MUIA_Radio_Active, attach->IsMIME ? 0 : 1);
  171.       nnset(gui->ST_CTYPE, MUIA_String_Contents, attach->ContentType);
  172.       nnset(gui->ST_DESC, MUIA_String_Contents, attach->Description);
  173.    }
  174. }
  175. MakeHook(WR_GetFileEntryHook, WR_GetFileEntry);
  176. ///
  177. /// WR_PutFileEntry
  178. //  Fills form data into selected list entry
  179. SAVEDS ASM void WR_PutFileEntry(REG(a1) int *arg)
  180. {
  181.    int winnum = *arg;
  182.    struct Attach *attach = NULL;
  183.    struct WR_GUIData *gui = &G->WR[winnum]->GUI;
  184.    int ismime;
  185.  
  186.    DoMethod(gui->LV_ATTACH, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &attach);
  187.    if (attach)
  188.    {
  189.       get(gui->RA_ENCODING, MUIA_Radio_Active, &ismime);
  190.       attach->IsMIME = ismime == 0;
  191.       GetMUIString(attach->ContentType, gui->ST_CTYPE);
  192.       GetMUIString(attach->Description, gui->ST_DESC);
  193.       DoMethod(gui->LV_ATTACH, MUIM_List_Redraw, MUIV_List_Redraw_Active);
  194.    }
  195. }
  196. MakeHook(WR_PutFileEntryHook, WR_PutFileEntry);
  197. ///
  198. /// WR_AddFileToList
  199. //  Adds a file to the attachment list, gets its size and type
  200. BOOL WR_AddFileToList(int winnum, char *filename, char *name, BOOL istemp)
  201. {
  202.    static struct Attach attach;
  203.    struct FileInfoBlock *fib;
  204.    struct WR_GUIData *gui = &G->WR[winnum]->GUI;
  205.    char *ctype;
  206.    int encoding;
  207.    BPTR lock;
  208.  
  209.    if (!filename) return FALSE;
  210.    clear(&attach, sizeof(struct Attach));
  211.    if (!(lock = Lock(filename, ACCESS_READ))) return FALSE;
  212.    fib = AllocDosObject(DOS_FIB, NULL);
  213.    Examine(lock, fib);
  214.    attach.Size = fib->fib_Size;
  215.    stccpy(attach.Description, fib->fib_Comment, SIZE_DEFAULT);
  216.    FreeDosObject(DOS_FIB, fib);
  217.    UnLock(lock);
  218.    ctype = IdentifyFile(filename);
  219.    if (*ctype)
  220.    {  
  221.       strcpy(attach.FilePath, filename); 
  222.       strcpy(attach.Name, name ? name : (char *)FilePart(filename));
  223.       get(gui->RA_ENCODING, MUIA_Radio_Active, &encoding);
  224.       attach.IsMIME = encoding == 0;
  225.       attach.IsTemp = istemp;
  226.       strcpy(attach.ContentType, ctype);
  227.       nnset(gui->ST_CTYPE, MUIA_String_Contents, attach.ContentType);
  228.       nnset(gui->ST_DESC, MUIA_String_Contents, attach.Description);
  229.       DoMethod(gui->LV_ATTACH, MUIM_List_InsertSingle, &attach, MUIV_List_Insert_Bottom);
  230.       set(gui->LV_ATTACH, MUIA_List_Active, MUIV_List_Active_Bottom);
  231.       return TRUE;
  232.    }
  233.    return FALSE;
  234. }  
  235. ///
  236.  
  237. /*** Compose Message ***/
  238. /// GetDateTime
  239. //  Formats current date and time for Date header field
  240. char *GetDateTime(void)
  241. {
  242.    static char dt[SIZE_DEFAULT];
  243.    char *tz;
  244.    time_t now;
  245.    struct tm tm;
  246.  
  247.    time(&now);
  248.    tm = *(localtime(&now));
  249.    sprintf(dt, "%s, %02ld %s %ld %02ld:%02ld:%02ld", wdays[tm.tm_wday], tm.tm_mday, months[tm.tm_mon], tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
  250.    if (tz = GetTZ()) { strcat(dt, " "); strcat(dt, tz); }
  251.    return dt;  
  252. }
  253. ///
  254. /// NewID
  255. //  Creates a unique id, used for Message-ID header field
  256. char *NewID(BOOL is_msgid) 
  257. {
  258.    static char idbuf[SIZE_MSGID];
  259.    static int ctr = 0;
  260.    struct DateStamp ds;
  261.  
  262.    DateStamp(&ds);
  263.    if (is_msgid) sprintf(idbuf, "yam%ld.%ld.%ld@%s", ds.ds_Days, ds.ds_Tick, FindTask(NULL), C->SMTP_Server);
  264.    else          sprintf(idbuf, "%ld.%ld", FindTask(NULL), ++ctr);
  265.    return idbuf;
  266. }
  267. ///
  268. /// WhichEncodingForFile
  269. //  Determines best MIME encoding mode for a file
  270. int WhichEncodingForFile(char *fname, char *ctype)
  271. {
  272.    int c, linesize=0, total=0, unsafechars=0, binarychars=0, longlines=0;
  273.    FILE *fh = fopen(fname, "r");
  274.  
  275.    if (!fh) return ENC_B64;
  276.    while ((c = fgetc(fh)) != -1)
  277.    {
  278.       if (c > 127) ++unsafechars;
  279.       if (c < 32 && c != '\t' && c != '\n' && c != '\r') ++binarychars;
  280.       ++total;
  281.       if (c == '\n') 
  282.       {
  283.          if (linesize > 79) ++longlines;
  284.          linesize = 0;
  285.       } else ++linesize;
  286.       if (total > 4000 && (longlines || unsafechars || binarychars)) break;
  287.    }
  288.    fclose(fh);
  289.    if (longlines || unsafechars || binarychars)
  290.    {
  291.       if (!strnicmp(ctype, "image/", 6) ||
  292.           !strnicmp(ctype, "audio/", 6) ||
  293.           !strnicmp(ctype, "application/octet-stream", 24) ||
  294.           !strnicmp(ctype, "video/", 6))
  295.          return ENC_B64;
  296.       if (!strnicmp(ctype, "message/", 8)) return (longlines) ? ENC_BIN : ENC_8BIT;
  297.       if (!unsafechars && !binarychars) return C->Allow8bit ? ENC_BIN : ENC_QP;
  298.       if (C->Allow8bit && !binarychars) return ENC_8BIT;
  299.       return (total/++unsafechars < 16) ? ENC_B64 : ENC_QP;
  300.    }
  301.    return ENC_NONE;
  302. }
  303. ///
  304. /// NewPart
  305. //  Initializes a new message part
  306. struct WritePart *NewPart(int winnum)
  307. {
  308.    struct WritePart *p;
  309.    p = (struct WritePart *)calloc(1,sizeof(struct WritePart));
  310.    p->ContentType = "text/plain";
  311.    p->EncType = ENC_NONE;
  312.    p->Filename = G->WR_Filename[winnum];
  313.    p->Name = NULL;
  314.    return p;
  315. }
  316. ///
  317. /// BuildPartsList
  318. //  Builds message parts from attachment list
  319. struct WritePart *BuildPartsList(int winnum)
  320. {
  321.    int i;
  322.    struct Attach *att;
  323.    struct WritePart *first, *p, *np;
  324.  
  325.    first = p = NewPart(winnum); p->IsTemp = TRUE;
  326.    p->EncType = WhichEncodingForFile(p->Filename, p->ContentType);
  327.    for (i = 0; ; i++)
  328.    {
  329.       DoMethod(G->WR[winnum]->GUI.LV_ATTACH, MUIM_List_GetEntry, i, &att);
  330.       if (!att) break;
  331.       p->Next = np = NewPart(winnum); p = np;
  332.       p->ContentType = att->ContentType;
  333.       p->Filename    = att->FilePath;
  334.       p->Description = att->Description;     
  335.       p->Name        = att->Name;
  336.       p->IsTemp      = att->IsTemp;
  337.       if (att->IsMIME) p->EncType = WhichEncodingForFile(p->Filename, p->ContentType);
  338.       else p->EncType = ENC_UUE;
  339.    }
  340.    return first;
  341. }
  342. ///
  343. /// FreePartsList
  344. //  Clears message parts and deletes temporary files
  345. void FreePartsList(struct WritePart *p)
  346. {
  347.    struct WritePart *np;
  348.    for (; p; p = np)
  349.    {
  350.       np = p->Next;
  351.       if (p->IsTemp) DeleteFile(p->Filename);
  352.       free(p);
  353.    }
  354. }
  355. ///
  356. /// WR_CharOut
  357. //  Outputs a single byte of a message header
  358. int WR_CharOut(char c)
  359. {
  360.    if (G->TTout) if (G->TTout->Header) return (int)G->TTout->Table[(UBYTE)c];
  361.    return (int)c;
  362. }
  363. ///
  364. /// firstbad
  365. //  Returns a pointer to the first non-ascii or control character in a string
  366. char *firstbad(char *s)
  367. {
  368.    unsigned char *dum;
  369.    for (dum = (unsigned char *)s; *dum; ++dum)
  370.       if (!isascii(WR_CharOut(*dum)) || iscntrl(WR_CharOut(*dum))) return (char *)dum;
  371.    return NULL;
  372. }
  373. ///
  374. /// PutQP
  375. //  Outputs a base64 encoded, single byte of a message header
  376. void PutQP(unsigned char c, FILE *fh)
  377. {
  378.    static char basis_hex[] = "0123456789ABCDEF";
  379.    fputc('=', fh);
  380.    fputc(basis_hex[c>>4], fh);
  381.    fputc(basis_hex[c&0xF], fh);
  382. }
  383. ///
  384. /// HeaderFputs
  385. //  Outputs the value of a header line (optional QP encoding and charset translation)
  386. void HeaderFputs(char *s, FILE *fh)
  387. {
  388.    char *firstnonascii, *wordstart;
  389.  
  390.    if (!s) return;
  391.    while (firstnonascii = firstbad(s))
  392.    {
  393.       for (wordstart = firstnonascii; wordstart >= s; wordstart--) if (ISpace(*wordstart)) break;
  394.       while (s <= wordstart) { fputc(WR_CharOut(*s), fh); ++s; }
  395.       fprintf(fh, "=?%s?Q?", G->TTout ? G->TTout->DestCharset : C->LocalCharset);
  396.       for (; *s && !ISpace(*s); ++s)
  397.       {
  398.          char c = (char)WR_CharOut(*s);
  399.          if (c > ' ') fputc(c, fh); else PutQP((unsigned char)c, fh);
  400.          }
  401.       fputs("?=", fh);
  402.    }
  403.    while (*s) { fputc(WR_CharOut(*s), fh); ++s; }
  404. }
  405. ///
  406. /// EmitHeader
  407. //  Outputs a complete header line
  408. void EmitHeader(FILE *fh, char *hdr, char *body)
  409. {
  410.    fprintf(fh, "%s: ", hdr);
  411.    HeaderFputs(body, fh);
  412.    fputc('\n', fh);
  413. }
  414. ///
  415. /// EmitRcptField
  416. //  Outputs the value of a recipient header line, one entry per line
  417. void EmitRcptField(FILE *fh, char *body)
  418. {
  419.    char *part, *next, *bodycpy = malloc(strlen(body)+1);
  420.  
  421.    strcpy(part = bodycpy, body);
  422.    while (part)
  423.    {
  424.       if (!*part) break;
  425.       if (next = MyStrChr(part, ',')) *next++ = 0;
  426.       HeaderFputs(Trim(part), fh);
  427.       if (part = next) fputs(",\n\t", fh);
  428.    }
  429.    free(bodycpy);
  430. ///
  431. /// EmitRcptHeader
  432. //  Outputs a complete recipient header line
  433. void EmitRcptHeader(FILE *fh, char *hdr, char *body)
  434. {
  435.    fprintf(fh, "%s: ", hdr);
  436.    EmitRcptField(fh, body ? body : "");
  437.    fputc('\n', fh);
  438. ///
  439. /// FPutsQuoting
  440. //  Handles quotes and slashes
  441. void FPutsQuoting(char *s, FILE *fh)
  442. {
  443.    char *end = s + strlen(s) - 1;
  444.    while (ISpace(*end) && end > s) --end;
  445.    if (*s == '\"') 
  446.    {
  447.       fputc(*s, fh);
  448.       while (*++s) 
  449.       {
  450.          if (*s == '\"') break;
  451.          if (*s == '\\') { fputc(*s, fh); ++s; if (!*s) break; }
  452.          fputc(*s, fh);
  453.       }
  454.       fputc('\"', fh);
  455.    }
  456.    else 
  457.    {
  458.       fputc('\"', fh); fputc(*s, fh);
  459.       while (*++s) 
  460.       {
  461.          if (*s == '\"' || *s == '\\') fputc('\\', fh);
  462.          fputc(*s, fh);
  463.       }
  464.       fputc('\"', fh);
  465.    }
  466. }
  467. ///
  468. /// WriteCtypeNicely
  469. //  Outputs content type
  470. void WriteCtypeNicely(FILE *fh, char *ct)
  471. {
  472.    char *semi, *slash, *eq, *s;
  473.  
  474.    for (s = ct; *s; ++s) if (*s == '\n') *s = ' ';
  475.    if (semi = (char *)index(ct, ';')) *semi = '\0';
  476.    slash = (char *)index(ct, '/');
  477.    fputs(ct, fh);
  478.    if (!slash) fputs("/unknown", fh);
  479.    while (semi) 
  480.    {
  481.       ct = semi + 1;
  482.       *semi = ';';
  483.       if (semi = (char *) index(ct, ';')) *semi = '\0';
  484.       if (eq = (char *) index(ct, '=')) *eq = '\0';
  485.       fputs(";\n\t", fh);
  486.       while (ISpace(*ct)) ++ct;
  487.       fputs(ct, fh);
  488.       if (eq) 
  489.       {
  490.          s = eq;
  491.          fputc('=', fh);
  492.          ++s;
  493.          while (ISpace(*s)) ++s;
  494.          FPutsQuoting(s, fh);
  495.          *eq = '=';
  496.       }
  497.    }
  498. }
  499. ///
  500. /// WriteContentTypeAndEncoding
  501. //  Outputs content type header including parameters
  502. void WriteContentTypeAndEncoding(FILE *fh, struct WritePart *part)
  503. {
  504.    char *p;
  505.    fputs("Content-Type: ", fh);
  506.    WriteCtypeNicely(fh, part->ContentType);
  507.    if (!strncmp(part->ContentType, "text/", 5) && (part->EncType != ENC_NONE || part->TTable))
  508.       fprintf(fh, "; charset=%s", part->TTable ? part->TTable->DestCharset : C->LocalCharset);
  509.    if (p = part->Name) if (*p) 
  510.    {
  511.       fputs("; name=\"", fh);
  512.       HeaderFputs(p, fh);
  513.       fputs("\"\nContent-Disposition: attachment; filename=\"", fh);
  514.       HeaderFputs(p, fh);
  515.       fputc('\"', fh);
  516.    }
  517.    fputc('\n', fh);
  518.    if (part->EncType != ENC_NONE)
  519.    {
  520.       fputs("Content-Transfer-Encoding: ", fh);
  521.       switch (part->EncType)
  522.       {
  523.          case ENC_B64:  fputs("base64\n", fh); break;
  524.          case ENC_QP:   fputs("quoted-printable\n", fh); break;
  525.          case ENC_UUE:  fputs("x-uue\n", fh); break;
  526.          case ENC_8BIT: fputs("8bit\n", fh); break;
  527.          case ENC_BIN:  fputs("binary\n", fh); break;
  528.       }
  529.    }
  530.    if (p = part->Description) if (*p) EmitHeader(fh, "Content-Description", p);
  531. }
  532. ///
  533. /// WR_WriteUIItem
  534. //  Outputs a single parameter of the X-SenderInfo header
  535. void WR_WriteUIItem(FILE *fh, int *len, char *parameter, char *value)
  536. {
  537.    int l = 6+strlen(parameter)+strlen(value);
  538.    *len += l;
  539.    fputc(';', fh); if (*len > 80) { fputs("\n  ", fh); *len = l; }
  540.    fprintf(fh, " %s=\"", parameter);
  541.    HeaderFputs(value, fh);
  542.    fputc('\"', fh);
  543. }
  544. ///
  545. /// WR_WriteUserInfo
  546. //  Outputs X-SenderInfo header line
  547. void WR_WriteUserInfo(FILE *fh)
  548. {
  549.    int len = 15, hits = 0;
  550.    struct ABEntry *ab = NULL;
  551.    struct MUIS_Listtree_TreeNode *tn;
  552.  
  553.    if (AB_SearchEntry(MUIV_Lt_GetEntry_ListNode_Root, C->EmailAddress, ASM_ADDRESS|ASM_USER, &hits, &tn))
  554.    {
  555.       ab = tn->tn_User;
  556.       if (ab->Type != AET_USER) ab = NULL;
  557.       else if (!*ab->Homepage && !*ab->Phone && !*ab->Street && !*ab->City && !*ab->Country && !ab->BirthDay) ab = NULL;
  558.    }
  559.    if (!ab && !*C->MyPictureURL) return;
  560.    fputs("X-SenderInfo: 1", fh);
  561.    if (*C->MyPictureURL) WR_WriteUIItem(fh, &len, "picture", C->MyPictureURL);
  562.    if (ab)
  563.    {
  564.       if (*ab->Homepage) WR_WriteUIItem(fh, &len, "homepage", ab->Homepage);
  565.       if (*ab->Street)   WR_WriteUIItem(fh, &len, "street", ab->Street);
  566.       if (*ab->City)     WR_WriteUIItem(fh, &len, "city", ab->City);
  567.       if (*ab->Country)  WR_WriteUIItem(fh, &len, "country", ab->Country);
  568.       if (*ab->Phone)    WR_WriteUIItem(fh, &len, "phone", ab->Phone);
  569.       if (ab->BirthDay)  fprintf(fh, "; dob=%ld", ab->BirthDay);
  570.    }
  571.    fputc('\n', fh);
  572. }
  573. ///
  574. /// EncodePart
  575. //  Encodes a message part
  576. void EncodePart(FILE *ofh, struct WritePart *part)
  577. {
  578.    FILE *ifh;
  579.  
  580.    if (ifh = fopen(part->Filename, "r"))
  581.    {
  582.       int size;
  583.       switch (part->EncType) 
  584.       {
  585.          case ENC_B64: to64(ifh, ofh, DoesNeedPortableNewlines(part->ContentType));
  586.                        break;
  587.          case ENC_QP:  toqp(ifh, ofh);
  588.                        break;
  589.          case ENC_UUE: size = FileSize(part->Filename);
  590.                        fprintf(ofh, "begin 644 %s\n", *part->Name ? part->Name : (char *)FilePart(part->Filename));
  591.                        touue(ifh, ofh);
  592.                        fprintf(ofh, "end\nsize %ld\n", size);
  593.                        break;
  594.          default:      CopyFile(NULL, ofh, NULL, ifh);
  595.       }
  596.       fclose(ifh);
  597.    }
  598. }
  599. ///
  600. /// WR_CreateHashTable
  601. //  Creates an index table for a database file
  602. BOOL WR_CreateHashTable(char *source, char *hashfile, char *sep)
  603. {
  604.    char buffer[SIZE_LARGE];
  605.    long fpos, l = strlen(sep);
  606.    FILE *in, *out;
  607.    BOOL success = FALSE;
  608.  
  609.    if (in = fopen(source, "r"))
  610.    {
  611.       if (out = fopen(hashfile, "w"))
  612.       {
  613.          fpos = 0; fwrite(&fpos, sizeof(long), 1, out);
  614.          while (fgets(buffer, SIZE_LARGE, in))
  615.             if (!strncmp(buffer, sep, l)) { fpos = ftell(in); fwrite(&fpos, sizeof(long), 1, out); }
  616.          success = TRUE;
  617.          fclose(out);
  618.       }
  619.       fclose(in);
  620.    }
  621.    return success;
  622. }
  623. ///
  624. /// WR_AddTagline
  625. //  Randomly selects a tagline and writes it to the message file
  626. void WR_AddTagline(FILE *fh_mail)
  627. {
  628.    FILE *fh_tag, *fh_hash;
  629.    char buf[SIZE_LARGE], hashfile[SIZE_PATHFILE];
  630.    long fpos, hsize;
  631.  
  632.    if (*C->TagsFile) 
  633.    {
  634.       sprintf(hashfile, "%s.hsh", C->TagsFile);
  635.       if (getft(C->TagsFile) > getft(hashfile)) WR_CreateHashTable(C->TagsFile, hashfile, C->TagsSeparator);
  636.       if (fh_tag = fopen(C->TagsFile, "r"))
  637.       {
  638.          if (fh_hash = fopen(hashfile, "r"))
  639.          {
  640.             fseek(fh_hash, 0, SEEK_END); hsize = ftell(fh_hash);
  641.             if ((hsize = hsize/sizeof(long)) > 1)
  642.             {
  643.                fpos = (((long)rand())%hsize)*sizeof(long);
  644.                fseek(fh_hash, fpos, SEEK_SET); fread(&fpos, sizeof(long), 1, fh_hash);
  645.                fseek(fh_tag, fpos, SEEK_SET);
  646.                if (GetLine(fh_tag, buf, SIZE_LARGE)) fprintf(fh_mail, buf);
  647.                while (GetLine(fh_tag, buf, SIZE_LARGE))
  648.                   if (!strncmp(buf, C->TagsSeparator, strlen(C->TagsSeparator))) break;
  649.                   else fprintf(fh_mail, "\n%s", buf);
  650.             }
  651.             fclose(fh_tag);
  652.          }
  653.          else ER_NewError(GetStr(MSG_ER_CantOpenFile), hashfile, NULL);
  654.       }
  655.       else ER_NewError(GetStr(MSG_ER_CantOpenFile), C->TagsFile, NULL);
  656.    }
  657. }
  658. ///
  659. /// WR_WriteSignature
  660. //  Writes signature to the message file
  661. void WR_WriteSignature(FILE *out, int signat)
  662. {
  663.    FILE *in;
  664.    int ch;
  665.    if (in = fopen(CreateFilename(SigNames[signat]), "r"))
  666.    {
  667.       fputs("-- \n", out);
  668.       while ((ch = fgetc(in)) != EOF)
  669.       {
  670.          if (ch == '%')
  671.          {
  672.             ch = fgetc(in);
  673.             if (ch == 't') { WR_AddTagline(out); continue; }
  674.             if (ch == 'e') { CopyFile(NULL, out, "ENV:SIGNATURE", NULL); continue; }
  675.             ungetc(ch, in); ch = '%';
  676.          }
  677.          fputc(ch, out);
  678.       }
  679.       fclose(in);
  680.    }
  681. }
  682. ///
  683. /// WR_AddSignature
  684. //  Adds a signature to the end of the file
  685. void WR_AddSignature(char *mailfile, int signat)
  686. {
  687.    FILE *fh_mail;
  688.    BOOL addline = FALSE;
  689.  
  690.    if (signat == -1) 
  691.    {
  692.       signat = C->UseSignature ? 1 : 0;
  693.       if (fh_mail = fopen(mailfile, "r"))
  694.       {
  695.          fseek(fh_mail, -1, SEEK_END);
  696.          addline = fgetc(fh_mail) != '\n';
  697.          fclose(fh_mail);
  698.       }
  699.    }
  700.    if (fh_mail = fopen(mailfile, "a"))
  701.    {
  702.       if (addline) fputc('\n', fh_mail);
  703.       if (signat) WR_WriteSignature(fh_mail, signat-1);
  704.       fclose(fh_mail);
  705.    }
  706. }
  707. ///
  708. /// WR_Anonymize
  709. //  Inserts recipient header field for remailer service
  710. void WR_Anonymize(FILE *fh, char *body)
  711. {
  712.    char *ptr;
  713.  
  714.    for (ptr = C->RMCommands; *ptr; ptr++)
  715.    {
  716.       if (*ptr == '\\') if (*(ptr+1) == 'n') { ptr++; fputs("\n", fh); continue; }
  717.       if (*ptr == '%') if (*(ptr+1) == 's') { ptr++; EmitRcptField(fh, body); continue; }
  718.       fputc(*ptr, fh);
  719.    }
  720.    fputs("\n", fh);
  721. }
  722. ///
  723. /// WR_GetPGPId
  724. //  Gets PGP key id for a person
  725. char *WR_GetPGPId(struct Person *pe)
  726. {
  727.    int hits;
  728.    char *pgpid = NULL;
  729.    struct MUIS_Listtree_TreeNode *tn;
  730.    if (!AB_SearchEntry(MUIV_Lt_GetEntry_ListNode_Root, pe->RealName, ASM_REALNAME|ASM_USER, &hits, &tn))
  731.         AB_SearchEntry(MUIV_Lt_GetEntry_ListNode_Root, pe->Address, ASM_ADDRESS|ASM_USER, &hits, &tn);
  732.    if (hits) if (((struct ABEntry *)(tn->tn_User))->PGPId[0]) pgpid = ((struct ABEntry *)(tn->tn_User))->PGPId;
  733.    return pgpid;
  734. }
  735. ///
  736. /// WR_GetPGPIds
  737. //  Collects PGP key ids for all persons in a recipient field
  738. char *WR_GetPGPIds(char *source, char *ids)
  739. {
  740.    struct Person pe;
  741.    char *next, *pid;
  742.  
  743.    for (; source; source = next)
  744.    {
  745.       if (!*source) break;
  746.       if (next = MyStrChr(source, ',')) *next++ = 0;
  747.       ExtractAddress(source, &pe);
  748.       if (!(pid = WR_GetPGPId(&pe)))
  749.       {
  750.          pid = pe.RealName[0] ? pe.RealName : pe.Address;
  751.          ER_NewError(GetStr(MSG_ER_ErrorNoPGPId), source, pid);
  752.       }
  753.       ids = StrBufCat(ids, (G->PGPVersion == 5) ? "-r \"" : "\"");
  754.       ids = StrBufCat(ids, pid);
  755.       ids = StrBufCat(ids, "\" ");
  756.    }
  757.    return ids;
  758. }
  759. ///
  760.  
  761. /// WR_Bounce
  762. //  Bounce message: inserts resent-headers while copying the message
  763. BOOL WR_Bounce(FILE *fh, struct Compose *comp)
  764. {
  765.    FILE *oldfh;
  766.    if (oldfh = fopen(GetMailFile(NULL, NULL, comp->OrigMail), "r"))
  767.    {
  768.       BOOL infield = FALSE, inbody = FALSE;
  769.       char buf[SIZE_LINE];
  770.       while (fgets(buf, SIZE_LINE, oldfh))
  771.       {
  772.          if (*buf == '\n' && !inbody)
  773.          {
  774.             inbody = TRUE;
  775.             EmitRcptHeader(fh, "To", comp->MailTo);
  776.             EmitHeader(fh, "Resent-From", BuildAddrName(C->EmailAddress, C->RealName));
  777.             EmitHeader(fh, "Resent-Date", GetDateTime());
  778.          }
  779.          if (!ISpace(*buf) && !inbody) infield = !strnicmp(buf, "to:", 3);
  780.          if (!infield || inbody) fputs(buf, fh);
  781.       }
  782.       fclose(oldfh);
  783.       return TRUE;
  784.    }
  785.    return FALSE;
  786. }
  787. ///
  788. /// WR_SaveDec
  789. //  Creates decrypted copy of a PGP encrypted message
  790. BOOL WR_SaveDec(FILE *fh, struct Compose *comp)
  791. {
  792.    FILE *oldfh;
  793.    if (oldfh = fopen(GetMailFile(NULL, NULL, comp->OrigMail), "r"))
  794.    {
  795.       BOOL infield = FALSE;
  796.       char buf[SIZE_LINE];
  797.       while (fgets(buf, SIZE_LINE, oldfh))
  798.       {
  799.          if (*buf == '\n') { fprintf(fh, "X-YAM-Decrypted: PGP; %s\n", GetDateTime()); break; }
  800.          if (!ISpace(*buf)) infield = !strnicmp(buf, "content-type:", 13)
  801.                                    || !strnicmp(buf, "content-transfer-encoding", 25)
  802.                                    || !strnicmp(buf, "mime-version:", 13);
  803.          if (!infield) fputs(buf, fh);
  804.       }
  805.       fclose(oldfh);
  806.       return TRUE;
  807.    }
  808.    return FALSE;
  809. }
  810. ///
  811. /// WR_EmitExtHeader
  812. //  Outputs special X-YAM-Header lines to remember user-defined headers
  813. void WR_EmitExtHeader(FILE *fh, struct Compose *comp)
  814. {
  815.    if (*comp->ExtHeader)
  816.    {
  817.       char *p, ch = '\n';
  818.       for (p = comp->ExtHeader; *p; ++p)
  819.       {
  820.          if (ch == '\n') fputs("X-YAM-Header-", fh);
  821.          if (*p != '\\') ch = *p;
  822.          else if (*++p == '\\') ch = '\\'; else if (*p == 'n') ch = '\n';
  823.          fputc(ch, fh);
  824.       }
  825.       if (ch != '\n') fputc('\n', fh);
  826.    }
  827. }
  828. ///
  829. /// WR_ComposeReport
  830. //  Assembles the parts of a message disposition notification
  831. const char *MIMEwarn = "Warning: This is a message in MIME format. Your mail reader does not\n"
  832.                        "support MIME. Some parts of this message will be readable as plain text.\n"
  833.                        "To see the rest, you will need to upgrade your mail reader. Following are\n"
  834.                        "some URLs where you can find MIME-capable mail programs for common platforms:\n\n"
  835.                        "  Amiga............: YAM          http://www.yam.ch/\n"
  836.                        "  Unix.............: Metamail     ftp://ftp.bellcore.com/nsb/\n"
  837.                        "  Windows/Macintosh: Eudora       http://www.qualcomm.com/\n\n"
  838.                        "General info about MIME can be found at:\n\n"
  839.                        "http://www.cis.ohio-state.edu/hypertext/faq/usenet/mail/mime-faq/top.html\n\n";
  840. const char *PGPwarn  = "The following body part contains a PGP encrypted message. Either your\n"
  841.                        "mail reader doesn't support MIME/PGP as specified in RFC 2015, or\n"
  842.                        "the message was encrypted for someone else. To read the encrypted\n"
  843.                        "message, run the next body part through Pretty Good Privacy.\n\n";
  844. void WR_ComposeReport(FILE *fh, struct Compose *comp, char *boundary)
  845. {
  846.    struct WritePart *p;
  847.    fprintf(fh, "Content-type: multipart/report; report-type=disposition-notification; boundary=\"%s\"\n\n", boundary);
  848.    for (p = comp->FirstPart; p; p = p->Next)
  849.    {
  850.       fprintf(fh, "\n--%s\n", boundary);
  851.       WriteContentTypeAndEncoding(fh, p);
  852.       fputs("\n", fh);
  853.       EncodePart(fh, p);
  854.    }
  855.    fprintf(fh, "\n--%s--\n\n", boundary);
  856. }
  857. ///
  858. /// WR_ComposePGP
  859. //  Creates a signed and/or encrypted PGP/MIME message
  860. BOOL WR_ComposePGP(FILE *fh, struct Compose *comp, char *boundary)
  861.  {
  862.    int sec = comp->Security;
  863.    BOOL success = FALSE;
  864.    struct WritePart pgppart, *firstpart = comp->FirstPart;
  865.    char *ids = AllocStrBuf(SIZE_DEFAULT), pgpfile[SIZE_PATHFILE], options[SIZE_LARGE];
  866.    struct TempFile *tf, *tf2 = NULL;
  867.  
  868.    pgppart.Filename = pgpfile; *pgpfile = 0;
  869.    pgppart.EncType = ENC_NONE;
  870.    if (sec & 2)
  871.    {
  872.       if (comp->MailTo) ids = WR_GetPGPIds(comp->MailTo, ids);
  873.       if (comp->MailCC) ids = WR_GetPGPIds(comp->MailCC, ids);
  874.       if (comp->MailBCC) ids = WR_GetPGPIds(comp->MailBCC, ids);
  875.       if (C->EncryptToSelf && *C->MyPGPID)
  876.       {
  877.          if (G->PGPVersion == 5) ids = StrBufCat(ids, "-r ");
  878.          ids = StrBufCat(ids, C->MyPGPID);
  879.       }
  880.    }
  881.    tf2 = OpenTempFile(NULL);
  882.    if (tf = OpenTempFile("w"))
  883.    {
  884.       WriteContentTypeAndEncoding(tf->FP, firstpart);
  885.       fputc('\n', tf->FP);
  886.       EncodePart(tf->FP, firstpart);
  887.       fclose(tf->FP); tf->FP = NULL;
  888.       ConvertCRLF(tf->Filename, tf2->Filename, TRUE);
  889.       CloseTempFile(tf);
  890.       sprintf(pgpfile, "%s.asc", tf2->Filename);
  891.       if (sec & 1) PGPGetPassPhrase();
  892.       switch (sec)
  893.       {
  894.          case 1: /* sign */
  895.             fprintf(fh, "Content-type: multipart/signed; boundary=\"%s\"; micalc=pgp-md5; protocol=\"application/pgp-signature\"\n\n%s\n--%s\n", boundary, MIMEwarn, boundary);
  896.             WriteContentTypeAndEncoding(fh, firstpart);
  897.             fputc('\n', fh);
  898.             EncodePart(fh, firstpart);
  899.             fprintf(fh, "\n--%s\nContent-Type: application/pgp-signature\n\n", boundary);
  900.             sprintf(options, (G->PGPVersion == 5) ? "-ab %s +batchmode=1 +force" : "-sab %s +bat +f", tf2->Filename);
  901.             if (*C->MyPGPID) { strcat(options, " -u "); strcat(options, C->MyPGPID); }
  902.             if (!PGPCommand((G->PGPVersion == 5) ? "pgps" : "pgp", options, 0)) success = TRUE;
  903.             break;
  904.          case 2: /* encrypt */
  905.             fprintf(fh, "Content-type: multipart/encrypted; boundary=\"%s\"; protocol=\"application/pgp-encrypted\"\n\n%s\n--%s\n", boundary, MIMEwarn, boundary);
  906.             fprintf(fh, "Content-Type: application/pgp-encrypted\n\nVersion: 1\n\n%s\n--%s\nContent-Type: application/octet-stream\n\n", PGPwarn, boundary);
  907.             sprintf(options, (G->PGPVersion == 5) ? "-a %s %s +batchmode=1 +force" : "-ea %s %s +bat +f", tf2->Filename, ids);
  908.             if (!PGPCommand((G->PGPVersion == 5) ? "pgpe" : "pgp", options, 0)) success = TRUE;
  909.             break;
  910.          case 3: /* sign+encrypt */
  911.             fprintf(fh, "Content-type: multipart/encrypted; boundary=\"%s\"; protocol=\"application/pgp-encrypted\"\n\n%s\n--%s\n", boundary, MIMEwarn, boundary);
  912.             fprintf(fh, "Content-Type: application/pgp-encrypted\n\nVersion: 1\n\n%s\n--%s\nContent-Type: application/octet-stream\n\n", PGPwarn, boundary);
  913.             sprintf(options, (G->PGPVersion == 5) ? "-a %s %s +batchmode=1 +force -s" : "-sea %s %s +bat +f", tf2->Filename, ids);
  914.             if (*C->MyPGPID) { strcat(options, " -u "); strcat(options, C->MyPGPID); }
  915.             if (!PGPCommand((G->PGPVersion == 5) ? "pgpe" : "pgp", options, 0)) success = TRUE;
  916.             break;
  917.       }
  918.       if (success) EncodePart(fh, &pgppart);
  919.    }
  920.    CloseTempFile(tf2);
  921.    if (*pgpfile) remove(pgpfile);
  922.    fprintf(fh, "\n--%s--\n\n", boundary);
  923.    FreeStrBuf(ids);
  924.    PGPClearPassPhrase(!success);
  925.    return success;
  926. }
  927. ///
  928. /// WR_ComposeMulti
  929. //  Assembles a multipart message
  930. void WR_ComposeMulti(FILE *fh, struct Compose *comp, char *boundary)
  931. {
  932.    struct WritePart *p;
  933.    fprintf(fh, "Content-type: multipart/mixed; boundary=\"%s\"\n\n", boundary);
  934.    fputs(MIMEwarn, fh);
  935.    for (p = comp->FirstPart; p; p = p->Next)
  936.    {
  937.       fprintf(fh, "\n--%s\n", boundary);
  938.       WriteContentTypeAndEncoding(fh, p);
  939.       if (comp->Security == 4) WR_Anonymize(fh, comp->MailTo);
  940.       fputs("\n", fh);
  941.       EncodePart(fh, p);
  942.    }
  943.    fprintf(fh, "\n--%s--\n\n", boundary);
  944. }
  945. ///
  946. /// WriteOutMessage
  947. //  Outputs header and body of a new message
  948. BOOL WriteOutMessage(struct Compose *comp)
  949. {
  950.    FILE *fh = comp->FH;
  951.    struct WritePart *firstpart = comp->FirstPart;
  952.    char boundary[SIZE_DEFAULT], options[SIZE_DEFAULT], *rcptto;
  953.    
  954.    if (comp->Mode == NEW_BOUNCE)
  955.    {
  956.       if (comp->DelSend) EmitHeader(fh, "X-YAM-Options", "delsent");
  957.       return WR_Bounce(fh, comp);
  958.    }
  959.    if (comp->Mode == NEW_SAVEDEC) if (!WR_SaveDec(fh, comp)) return FALSE; else goto mimebody;
  960.    if (!firstpart) return FALSE;
  961.    if (firstpart->Next && comp->Security >= 1 && comp->Security <= 3)
  962.    {
  963.       ER_NewError(GetStr(MSG_WR_PGPMIMEconflict), NULL, NULL);
  964.       comp->Security = 0;
  965.    }
  966.    *options = 0;
  967.    if (comp->DelSend) strcat(options, ",delsent");
  968.    if (comp->Security) sprintf(&options[strlen(options)], ",%s", SecCodes[comp->Security]);
  969.    if (comp->Signature) sprintf(&options[strlen(options)], ",sigfile%ld", comp->Signature-1);
  970.    if (*options) EmitHeader(fh, "X-YAM-Options", &options[1]);
  971.    EmitHeader(fh, "From", comp->From ? comp->From : BuildAddrName(C->EmailAddress, C->RealName));
  972.    if (comp->ReplyTo) EmitHeader(fh, "Reply-To", comp->ReplyTo);
  973.    if (comp->MailTo) EmitRcptHeader(fh, "To", comp->Security == 4 ? C->ReMailer : comp->MailTo);
  974.    if (comp->MailCC) EmitRcptHeader(fh, "CC", comp->MailCC);
  975.    if (comp->MailBCC) EmitRcptHeader(fh, "BCC", comp->MailBCC);
  976.    EmitHeader(fh, "Date", GetDateTime());
  977.    fprintf(fh, "Message-ID: <%s>\n", NewID(True));
  978.    if (comp->IRTMsgID) EmitHeader(fh, "In-Reply-To", comp->IRTMsgID);
  979.    rcptto = comp->ReplyTo ? comp->ReplyTo : (comp->From ? comp->From : C->EmailAddress);
  980.    if (comp->Receipt & 1) EmitHeader(fh, "Return-Receipt-To", rcptto);
  981.    if (comp->Receipt & 2) EmitHeader(fh, "Disposition-Notification-To", rcptto);
  982.    if (comp->Importance) EmitHeader(fh, "Importance", comp->Importance == 1 ? "High" : "Low");
  983.    fprintf(fh, "X-Mailer: YAM %s AmigaOS E-Mail Client (c) 1995-2000 by Marcel Beck  http://www.yam.ch\n", __VERSION__);
  984.    if (comp->UserInfo) WR_WriteUserInfo(fh);
  985.    if (*C->Organization) EmitHeader(fh, "Organization", C->Organization);
  986.    if (*comp->Subject) EmitHeader(fh, "Subject", comp->Subject);
  987.    if (comp->ExtHeader) WR_EmitExtHeader(fh, comp);
  988. mimebody:
  989.    fputs("MIME-Version: 1.0\n", fh);
  990.    sprintf(boundary, "BOUNDARY.%s", NewID(False));
  991.    if (comp->ReportType > 0) WR_ComposeReport(fh, comp, boundary);
  992.    else if (comp->Security >= 1 && comp->Security <= 3) return WR_ComposePGP(fh, comp, boundary);
  993.    else if (firstpart->Next) WR_ComposeMulti(fh, comp, boundary);
  994.    else
  995.    {
  996.       WriteContentTypeAndEncoding(fh, firstpart);
  997.       if (comp->Security == 4 && comp->OldSecurity != 4) WR_Anonymize(fh, comp->MailTo);
  998.       fputs("\n", fh);
  999.       EncodePart(fh, firstpart);
  1000.    }
  1001.    return TRUE;
  1002. }
  1003. ///
  1004. /// WR_AutoSaveFile
  1005. //  Returns filename of the auto-save file
  1006. char *WR_AutoSaveFile(int winnr)
  1007. {
  1008.    static char fname[SIZE_PATHFILE];
  1009.    strmfp(fname, G->ProgDir, ".autosave");
  1010.    strcat(fname, itoa(winnr));
  1011.    strcat(fname, ".txt");
  1012.    return fname;
  1013. }
  1014. ///
  1015.  
  1016. /*** Buttons ***/
  1017. /// WR_NewMail
  1018. //  Validates write window options and generates a new message
  1019. void WR_NewMail(int mode, int winnum)
  1020. {
  1021.    struct Compose comp;
  1022.    char *addr, *er;
  1023.    static struct Mail mail;
  1024.    struct Mail *new = NULL, *mlist[3];
  1025.    int i, att = 0;
  1026.    struct WR_ClassData *wr = G->WR[winnum];
  1027.    struct WR_GUIData *gui = &wr->GUI;
  1028.    struct Folder *outfolder = FO_GetFolderByType(FT_OUTGOING, NULL);
  1029.  
  1030.    set(gui->RG_PAGE, MUIA_Group_ActivePage, 0);
  1031.    clear(&mail, sizeof(struct Mail));
  1032.    clear(&comp, sizeof(struct Compose));
  1033.    mlist[0] = (struct Mail *)1; mlist[1] = NULL;
  1034.    get(gui->ST_TO, MUIA_String_Contents, &addr);
  1035.    er = GetStr(MSG_WR_ErrorNoRcpt);
  1036.    if (!*addr) if (MUI_Request(G->App, gui->WI, 0, NULL, GetStr(MSG_WR_NoRcptReqGad), er)) mode = WRITE_HOLD;
  1037.       else return;
  1038.    Busy(GetStr(MSG_BusyComposing), "", 0, 0);
  1039.    get(gui->ST_SUBJECT, MUIA_String_Contents, &comp.Subject);
  1040.    comp.Mode = wr->Mode;
  1041.    comp.OrigMail = wr->Mail;
  1042.    comp.OldSecurity = wr->OldSecurity;
  1043.    wr->ListEntry = NULL;
  1044.    if (*addr) if (!(comp.MailTo = WR_ExpandAddresses(winnum, addr, FALSE, FALSE))) goto skip;
  1045.    if (wr->Mode != NEW_BOUNCE)
  1046.    {
  1047.       get(gui->ST_CC, MUIA_String_Contents, &addr);
  1048.       if (*addr) if (!(comp.MailCC = WR_ExpandAddresses(winnum, addr, FALSE, FALSE))) goto skip;
  1049.       get(gui->ST_BCC, MUIA_String_Contents, &addr);
  1050.       if (*addr) if (!(comp.MailBCC = WR_ExpandAddresses(winnum, addr, FALSE, FALSE))) goto skip;
  1051.       get(gui->ST_FROM, MUIA_String_Contents, &addr);
  1052.       if (*addr) if (!(comp.From = WR_ExpandAddresses(winnum, addr, FALSE, TRUE))) goto skip;
  1053.       get(gui->ST_REPLYTO, MUIA_String_Contents, &addr);
  1054.       if (*addr) if (!(comp.ReplyTo = WR_ExpandAddresses(winnum, addr, FALSE, TRUE))) goto skip;
  1055.       get(gui->ST_EXTHEADER, MUIA_String_Contents, &comp.ExtHeader);
  1056.       if (wr->ListEntry)
  1057.       {
  1058.          if (wr->ListEntry->Address[0]) comp.ReplyTo = StrBufCpy(NULL, wr->ListEntry->Address);
  1059.          if (wr->ListEntry->RealName[0]) comp.From = StrBufCpy(comp.From, BuildAddrName(C->EmailAddress, wr->ListEntry->RealName));
  1060.       }
  1061.       if (wr->MsgID[0]) comp.IRTMsgID = wr->MsgID;
  1062.       comp.Importance = 1-GetMUICycle(gui->CY_IMPORTANCE);
  1063.       if (GetMUICheck(gui->CH_RECEIPT)) comp.Receipt |= 1;
  1064.       if (GetMUICheck(gui->CH_DISPNOTI)) comp.Receipt |= 2;
  1065.       comp.Signature = GetMUIRadio(gui->RA_SIGNATURE);
  1066.       comp.Security = GetMUIRadio(gui->RA_SECURITY);
  1067.       comp.DelSend = GetMUICheck(gui->CH_DELSEND);
  1068.       comp.UserInfo = GetMUICheck(gui->CH_ADDINFO);
  1069.       get(G->WR[winnum]->GUI.LV_ATTACH, MUIA_List_Entries, &att);
  1070.       EditorToFile(gui->TE_EDIT, G->WR_Filename[winnum], G->TTout);
  1071.       comp.FirstPart = BuildPartsList(winnum);
  1072.       comp.FirstPart->TTable = G->TTout;
  1073.    }
  1074.    if (wr->Mode == NEW_EDIT)
  1075.    {
  1076.       struct Mail *edmail = wr->Mail;
  1077.       outfolder = edmail->Folder;
  1078.       if (MailExists(edmail, NULL))
  1079.       {
  1080.          comp.FH = fopen(GetMailFile(NULL, outfolder, edmail), "w");
  1081.          strcpy(mail.MailFile, edmail->MailFile);
  1082.       }
  1083.       else
  1084.       {
  1085.          wr->Mode = NEW_NEW;
  1086.          comp.FH = fopen(MA_NewMailFile(outfolder, mail.MailFile, 0), "w");
  1087.       }
  1088.    }
  1089.    else comp.FH = fopen(MA_NewMailFile(outfolder, mail.MailFile, 0), "w");
  1090.    if (comp.FH)
  1091.    {
  1092.       struct MailInfo *mi;
  1093.       struct ExtendedMail *email;
  1094.       int stat = mode == WRITE_HOLD ? STATUS_HLD : STATUS_WFS;
  1095.       BOOL done = WriteOutMessage(&comp);
  1096.       fclose(comp.FH);
  1097.       if (!done) { DeleteFile(GetMailFile(NULL, outfolder, &mail)); goto skip; }
  1098.       if (wr->Mode != NEW_BOUNCE) EndNotify(&G->WR_NRequest[winnum]);
  1099.       if (email = MA_ExamineMail(outfolder, mail.MailFile, Status[stat], FALSE))
  1100.       {
  1101.          new = AddMailToList((struct Mail *)email, outfolder);
  1102.          MA_FreeEMailStruct(email);
  1103.          if (FO_GetCurrentFolder() == outfolder) DoMethod(G->MA->GUI.NL_MAILS, MUIM_NList_InsertSingle, new, MUIV_NList_Insert_Sorted);
  1104.          MA_SetMailStatus(new, stat);
  1105.          if (wr->Mode == NEW_EDIT)
  1106.          {
  1107.             mi = GetMailInfo(wr->Mail);
  1108.             if (mi->Display) DoMethod(G->MA->GUI.NL_MAILS, MUIM_NList_Remove, mi->Pos);
  1109.             RemoveMailFromList(wr->Mail);
  1110.             wr->Mail = new;
  1111.          }
  1112.       }
  1113.       if (wr->Mode != NEW_NEW)
  1114.       {
  1115.          struct Mail *m, **ml = wr->MList ? wr->MList : mlist;
  1116.          mlist[2] = wr->Mail;
  1117.          for (i = 0; i < (int)ml[0]; i++)
  1118.          {
  1119.             m = ml[i+2];
  1120.             if (!Virtual(m)) if (m->Folder->Type != FT_OUTGOING && m->Folder->Type != FT_SENT)
  1121.             {
  1122.                if (m->Status == STATUS_NEW || m->Status == STATUS_UNR)
  1123.                {
  1124.                   int mdntype = wr->Mode == NEW_REPLY ? MDN_DISP : MDN_PROC;
  1125.                   if (winnum == 2) mdntype |= MDN_AUTOACT;
  1126.                   RE_DoMDN(mdntype, m);
  1127.                }
  1128.                switch (wr->Mode)
  1129.                {
  1130.                   case NEW_REPLY:  MA_SetMailStatus(m, STATUS_RPD);
  1131.                                    DisplayStatistics(m->Folder); break;
  1132.                   case NEW_FORWARD:
  1133.                   case NEW_BOUNCE: MA_SetMailStatus(m, STATUS_FWD);
  1134.                                    DisplayStatistics(m->Folder); break;
  1135.                }
  1136.             }
  1137.          }
  1138.       }
  1139.       switch (wr->Mode)
  1140.       {
  1141.          case NEW_NEW:     AppendLog(10, GetStr(MSG_LOG_Creating),   AddrName(new->To), new->Subject, (void *)att, ""); break;
  1142.          case NEW_REPLY:   AppendLog(11, GetStr(MSG_LOG_Replying),   AddrName(wr->MList[2]->From), wr->MList[2]->Subject, "", ""); break;
  1143.          case NEW_FORWARD: AppendLog(12, GetStr(MSG_LOG_Forwarding), AddrName(wr->MList[2]->From), wr->MList[2]->Subject, AddrName(new->To), ""); break;
  1144.          case NEW_BOUNCE:  AppendLog(13, GetStr(MSG_LOG_Bouncing),   AddrName(wr->Mail->From), wr->Mail->Subject, AddrName(new->To), ""); break;
  1145.          case NEW_EDIT:    AppendLog(14, GetStr(MSG_LOG_Editing),    AddrName(new->From), AddrName(new->To), new->Subject, ""); break;
  1146.       }
  1147.       MA_StartMacro(MACRO_POSTWRITE, itoa(winnum));
  1148.    }
  1149.    else ER_NewError(GetStr(MSG_ER_CreateMailError), NULL, NULL);
  1150.    FreePartsList(comp.FirstPart);
  1151.    if (wr->MList) free(wr->MList);
  1152.    if (mode == WRITE_SEND && new && !G->TR)
  1153.    {
  1154.       set(gui->WI, MUIA_Window_Open, FALSE);
  1155.       mlist[2] = new; MA_SendMList(mlist);
  1156.    }
  1157.    DeleteFile(WR_AutoSaveFile(winnum));
  1158.    DisposeModulePush(&G->WR[winnum]);
  1159. skip:
  1160.    FreeStrBuf(comp.MailTo);
  1161.    FreeStrBuf(comp.MailCC);
  1162.    FreeStrBuf(comp.MailBCC);
  1163.    FreeStrBuf(comp.From);
  1164.    FreeStrBuf(comp.ReplyTo);
  1165.    DisplayStatistics(outfolder);
  1166.    BusyEnd;
  1167. }
  1168. SAVEDS ASM void WR_NewMailFunc(REG(a1) int *arg)
  1169. {
  1170.    WR_NewMail(arg[0], arg[1]);
  1171. }
  1172. MakeHook(WR_NewMailHook, WR_NewMailFunc);
  1173. ///
  1174. /// WR_Cleanup
  1175. //  Terminates file notification and removes temporary files
  1176. void WR_Cleanup(int winnum)
  1177. {
  1178.    int i;
  1179.    struct Attach *att;
  1180.    if (G->WR[winnum]->Mode != NEW_BOUNCE)
  1181.    {
  1182.       EndNotify(&G->WR_NRequest[winnum]);
  1183.       DeleteFile(G->WR_Filename[winnum]);
  1184.       for (i = 0; ; i++)
  1185.       {
  1186.          DoMethod(G->WR[winnum]->GUI.LV_ATTACH, MUIM_List_GetEntry, i, &att);
  1187.          if (!att) break;
  1188.          if (att->IsTemp) DeleteFile(att->FilePath);
  1189.       }
  1190.    }
  1191. }
  1192. ///
  1193. /// WR_CancelFunc
  1194. //  User clicked the Cancel button
  1195. SAVEDS ASM void WR_CancelFunc(REG(a1) int *arg)
  1196. {
  1197.    int haschanged, winnum = *arg;
  1198.    if (G->WR[winnum]->Mode != NEW_BOUNCE)
  1199.    {
  1200.       if (winnum < 2)
  1201.       {
  1202.          get(G->WR[winnum]->GUI.TE_EDIT, MUIA_TextEditor_HasChanged, &haschanged);
  1203.          if (haschanged)
  1204.             switch (MUI_Request(G->App, G->WR[winnum]->GUI.WI, 0, NULL, GetStr(MSG_WR_DiscardChangesGad), GetStr(MSG_WR_DiscardChanges)))
  1205.             {
  1206.                case 0: return;
  1207.                case 1: WR_NewMail(WRITE_QUEUE, winnum);
  1208.                        return;
  1209.                case 2: break;
  1210.             }
  1211.       }
  1212.       WR_Cleanup(winnum);
  1213.    }
  1214.    DisposeModulePush(&G->WR[winnum]);
  1215. }
  1216. MakeHook(WR_CancelHook, WR_CancelFunc);
  1217. ///
  1218. /// WR_SaveAsFunc
  1219. //  Saves contents of internal editor to a file
  1220. SAVEDS ASM void WR_SaveAsFunc(REG(a1) int *arg)
  1221. {
  1222.    int winnum = *arg;
  1223.    set(G->WR[winnum]->GUI.RG_PAGE, MUIA_Group_ActivePage, 0);
  1224.    if (ReqFile(ASL_ATTACH, G->WR[winnum]->GUI.WI, GetStr(MSG_WR_SaveTextAs), 1, C->AttachDir, ""))
  1225.    {
  1226.       char filename[SIZE_PATHFILE];
  1227.       strmfp(filename, G->ASLReq[ASL_ATTACH]->fr_Drawer, G->ASLReq[ASL_ATTACH]->fr_File);
  1228.       EditorToFile(G->WR[winnum]->GUI.TE_EDIT, G->WR_Filename[winnum], NULL);
  1229.       if (!CopyFile(filename, NULL, G->WR_Filename[winnum], NULL))
  1230.          ER_NewError(GetStr(MSG_ER_CantCreateFile), filename, NULL);
  1231.    }
  1232. }
  1233. MakeHook(WR_SaveAsHook, WR_SaveAsFunc);
  1234. ///
  1235. /// WR_Edit
  1236. //  Launches external editor with message text
  1237. SAVEDS ASM void WR_Edit(REG(a1) int *arg)
  1238. {
  1239.    int winnum = *arg;
  1240.    if (*(C->Editor))
  1241.    {
  1242.       char buffer[SIZE_COMMAND+SIZE_PATHFILE];
  1243.       set(G->WR[winnum]->GUI.RG_PAGE, MUIA_Group_ActivePage, 0);
  1244.       EditorToFile(G->WR[winnum]->GUI.TE_EDIT, G->WR_Filename[winnum], NULL);
  1245.       sprintf(buffer,"%s \"%s\"", C->Editor, G->WR_Filename[winnum]);
  1246.       ExecuteCommand(buffer, TRUE, OUT_NIL);
  1247.    }
  1248. }
  1249. MakeHook(WR_EditHook, WR_Edit);
  1250. ///
  1251. /// WR_AddFileFunc
  1252. //  Adds one or more files to the attachment list
  1253. SAVEDS ASM void WR_AddFileFunc(REG(a1) int *arg)
  1254. {
  1255.    int i, winnum = *arg;
  1256.    char filename[SIZE_PATHFILE];
  1257.    struct FileRequester *ar = G->ASLReq[ASL_ATTACH];
  1258.  
  1259.    if (ReqFile(ASL_ATTACH, G->WR[winnum]->GUI.WI, GetStr(MSG_WR_AddFile), 2, C->AttachDir, ""))
  1260.       if (!ar->fr_NumArgs)
  1261.       {
  1262.          strmfp(filename, G->ASLReq[ASL_ATTACH]->fr_Drawer, G->ASLReq[ASL_ATTACH]->fr_File);
  1263.          WR_AddFileToList(winnum, filename, NULL, FALSE);
  1264.       }
  1265.       else for (i = 0; i < ar->fr_NumArgs; i++)
  1266.       {
  1267.          strmfp(filename, G->ASLReq[ASL_ATTACH]->fr_Drawer, G->ASLReq[ASL_ATTACH]->fr_ArgList[i].wa_Name);
  1268.          WR_AddFileToList(winnum, filename, NULL, FALSE);
  1269.       }
  1270. }
  1271. MakeHook(WR_AddFileHook, WR_AddFileFunc);
  1272. ///
  1273. /// WR_AddArchiveFunc
  1274. //  Creates an archive of one or more files and adds it to the attachment list
  1275. SAVEDS ASM void WR_AddArchiveFunc(REG(a1) int *arg)
  1276. {
  1277.    int i, winnum = *arg;
  1278.    static char chr[2] = { 0,0 };
  1279.    char *src, *dst, filename[SIZE_PATHFILE], arcpath[SIZE_PATHFILE], arcname[SIZE_FILE];
  1280.    struct TempFile *tf = NULL;
  1281.    struct FileRequester *ar = G->ASLReq[ASL_ATTACH];
  1282.    BPTR olddir, filedir;
  1283.  
  1284.    if (ReqFile(ASL_ATTACH, G->WR[winnum]->GUI.WI, GetStr(MSG_WR_AddFile), 2, C->AttachDir, ""))
  1285.    {
  1286.       strsfn(ar->fr_ArgList[0].wa_Name, NULL, NULL, arcname, NULL);
  1287.       if (!*arcname) strsfn(ar->fr_ArgList[0].wa_Name, NULL, NULL, NULL, arcname);
  1288.       if (!StringRequest(arcname, SIZE_FILE, GetStr(MSG_WR_CreateArc), GetStr(MSG_WR_CreateArcReq), GetStr(MSG_Okay), NULL, GetStr(MSG_Cancel), FALSE, G->WR[winnum]->GUI.WI)) return;
  1289.       strmfp(filename, C->TempDir, arcname);
  1290.       sprintf(arcpath, strchr(filename, ' ') ? "\"%s\"" : "%s", filename);
  1291.       if (strstr(C->PackerCommand, "%l")) if (tf = OpenTempFile("w"))
  1292.       {
  1293.          for (i = 0; i < ar->fr_NumArgs; i++)
  1294.          {
  1295. //            strmfp(filename, ar->fr_Drawer, ar->fr_ArgList[i].wa_Name);
  1296. //            fprintf(tf->FP, strchr(filename, ' ') ? "\"%s\"\n" : "%s\n", filename);
  1297.             fprintf(tf->FP, strchr(ar->fr_ArgList[i].wa_Name, ' ') ? "\"%s\"\n" : "%s\n", ar->fr_ArgList[i].wa_Name);
  1298.          }
  1299.          fclose(tf->FP); tf->FP = NULL;
  1300.       }
  1301.       dst = AllocStrBuf(SIZE_DEFAULT);
  1302.       for (src = C->PackerCommand; *src; src++)
  1303.          if (*src == '%') switch (*++src)
  1304.          {
  1305.             case '%': dst = StrBufCat(dst, "%"); break;
  1306.             case 'a': dst = StrBufCat(dst, arcpath); break;
  1307.             case 'l': dst = StrBufCat(dst, tf->Filename); break;
  1308.             case 'f': for (i = 0; i < ar->fr_NumArgs; i++)
  1309.                       {
  1310. //                         strcpy(filename, "\"");
  1311. //                         strmfp(&filename[1], ar->fr_Drawer, ar->fr_ArgList[i].wa_Name);
  1312. //                         strcat(filename, "\" ");
  1313.                          sprintf(filename, "\"%s\"", ar->fr_ArgList[i].wa_Name);
  1314.                          dst = StrBufCat(dst, filename);
  1315.                       }
  1316.                       break;
  1317.          }
  1318.          else
  1319.          {
  1320.             chr[0] = *src;
  1321.             dst = StrBufCat(dst, chr);
  1322.          }
  1323.       filedir = Lock(ar->fr_Drawer, ACCESS_READ); olddir = CurrentDir(filedir);
  1324.       ExecuteCommand(dst, FALSE, OUT_NIL);
  1325.       CurrentDir(olddir); UnLock(filedir);
  1326.       FreeStrBuf(dst);
  1327.       CloseTempFile(tf);
  1328.       strcpy(filename, arcpath);
  1329.       if (FileSize(filename) == -1)
  1330.       {
  1331.          sprintf(filename, "%s.lha", arcpath);
  1332.          if (FileSize(filename) == -1)
  1333.          {
  1334.             sprintf(filename, "%s.lzx", arcpath);
  1335.             if (FileSize(filename) == -1)
  1336.                sprintf(filename, "%s.zip", arcpath);
  1337.          }
  1338.       }
  1339.       WR_AddFileToList(winnum, filename, NULL, TRUE);
  1340.    }
  1341. }
  1342. MakeHook(WR_AddArchiveHook, WR_AddArchiveFunc);
  1343. ///
  1344. /// WR_DisplayFile
  1345. //  Displays an attached file using a MIME viewer
  1346. SAVEDS ASM void WR_DisplayFile(REG(a1) int *arg)
  1347. {
  1348.    struct Attach *attach = NULL;
  1349.  
  1350.    DoMethod(G->WR[*arg]->GUI.LV_ATTACH, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &attach);
  1351.    if (attach) RE_DisplayMIME(attach->FilePath, attach->ContentType);
  1352. }
  1353. MakeHook(WR_DisplayFileHook, WR_DisplayFile);
  1354. ///
  1355. /// WR_ChangeSignatureFunc
  1356. //  Changes the current signature
  1357. SAVEDS ASM void WR_ChangeSignatureFunc(REG(a1) int *arg)
  1358. {
  1359.    struct TempFile *tf;
  1360.    int signat = arg[0], winnum = arg[1];
  1361.    char buffer[SIZE_LINE];
  1362.    FILE *in, *out;
  1363.  
  1364.    if (tf = OpenTempFile(NULL))
  1365.    {
  1366.       EditorToFile(G->WR[winnum]->GUI.TE_EDIT, tf->Filename, NULL);
  1367.       if (in = fopen(tf->Filename, "r"))
  1368.       {
  1369.          if (out = fopen(G->WR_Filename[winnum], "w"))
  1370.          {
  1371.             while (fgets(buffer, SIZE_LINE, in))
  1372.                if (strcmp(buffer, "-- \n")) fputs(buffer, out); else break;
  1373.             if (signat) WR_WriteSignature(out, signat-1);
  1374.             fclose(out);
  1375.          }
  1376.          fclose(in);
  1377.       }
  1378.       CloseTempFile(tf);;
  1379.    }
  1380. }
  1381. MakeHook(WR_ChangeSignatureHook, WR_ChangeSignatureFunc);
  1382. ///
  1383.  
  1384. /*** Menus ***/
  1385. /// WR_TransformText
  1386. //  Inserts or pastes text as plain, ROT13 or quoted
  1387. char *WR_TransformText(char *source, int mode, char *qtext)
  1388. {
  1389.    FILE *fp;
  1390.    char *dest = NULL;
  1391.    int ch, i, size = FileSize(source), pos = 0, p = 0, qtextlen = strlen(qtext);
  1392.  
  1393.    if (size > 0)
  1394.    {
  1395.       size += SIZE_DEFAULT;
  1396.       if (mode == ED_INSQUOT || mode == ED_PASQUOT) size += size/20*qtextlen;
  1397.       if (dest = calloc(size, 1))
  1398.       {
  1399.          if (fp = fopen(source, "r"))
  1400.          {
  1401.             while ((ch = fgetc(fp)) != EOF)
  1402.             {
  1403.                if (!pos && (mode == ED_INSQUOT || mode == ED_PASQUOT))
  1404.                {
  1405.                   if (p+qtextlen > size-2) dest = realloc(dest,(size += SIZE_LARGE));
  1406.                   for (i = 0; i < qtextlen; i++) dest[p++] = qtext[i]; dest[p++] = ' ';
  1407.                }
  1408.                if (ch == '\n') pos = 0; else ++pos;
  1409.                if (mode == ED_INSROT13 || mode == ED_PASROT13)
  1410.                {
  1411.                   if (ch >= 'a' && ch <= 'z') if ((ch += 13) > 'z') ch -= 26;
  1412.                   if (ch >= 'A' && ch <= 'Z') if ((ch += 13) > 'Z') ch -= 26;
  1413.                }
  1414.                if (p > size-3) dest = realloc(dest,(size += SIZE_LARGE));
  1415.                dest[p++] = ch;
  1416.             }
  1417.             dest[p] = 0;
  1418.             fclose(fp);
  1419.          }
  1420.       }
  1421.    }
  1422.    return dest;
  1423. }
  1424. ///
  1425. /// WR_InsertSeparator
  1426. //  Inserts a separator bar at the cursor position
  1427. SAVEDS ASM void WR_InsertSeparatorFunc(REG(a1) int *arg)
  1428. {
  1429.    APTR ed = G->WR[arg[1]]->GUI.TE_EDIT;
  1430.    set(ed, MUIA_TextEditor_ImportHook, MUIV_TextEditor_ImportHook_Plain);
  1431.    DoMethod(ed, MUIM_TextEditor_InsertText, arg[0] ? "\n\033c\033[s:18]\n" : "\n\033c\033[s:2]\n");
  1432.    set(ed, MUIA_TextEditor_ImportHook, MUIV_TextEditor_ImportHook_EMail);
  1433. }
  1434. MakeHook(WR_InsertSeparatorHook, WR_InsertSeparatorFunc);
  1435. ///
  1436. /// WR_EditorCmd
  1437. //  Inserts file or clipboard into editor
  1438. SAVEDS ASM void WR_EditorCmd(REG(a1) int *arg)
  1439. {
  1440.    int cmd = arg[0], winnum = arg[1];
  1441.    char *text, filename[SIZE_PATHFILE];
  1442.    struct TempFile *tf;
  1443.    struct WR_ClassData *wr = G->WR[winnum];
  1444.  
  1445.    if (cmd == ED_INSERT || cmd == ED_INSQUOT || cmd == ED_INSROT13 || cmd == ED_OPEN)
  1446.    {
  1447.       if (!ReqFile(ASL_ATTACH, wr->GUI.WI, GetStr(MSG_WR_InsertFile), 0, C->AttachDir, "")) return;
  1448.       strmfp(filename, G->ASLReq[ASL_ATTACH]->fr_Drawer, G->ASLReq[ASL_ATTACH]->fr_File);
  1449.       text = WR_TransformText(filename, cmd, wr->QuoteText);
  1450.    }
  1451.    else
  1452.    {
  1453.       if (!(tf = OpenTempFile("w"))) return;
  1454.       DumpClipboard(tf->FP);
  1455.       fclose(tf->FP); tf->FP = NULL;
  1456.       text = WR_TransformText(tf->Filename, cmd, wr->QuoteText);
  1457.       CloseTempFile(tf);
  1458.    }
  1459.    if (text)
  1460.    {
  1461.       if (cmd == ED_OPEN) DoMethod(wr->GUI.TE_EDIT, MUIM_TextEditor_ClearText);
  1462.       DoMethod(wr->GUI.TE_EDIT, MUIM_TextEditor_InsertText, text);
  1463.       free(text);
  1464.    }
  1465. }
  1466. MakeHook(WR_EditorCmdHook, WR_EditorCmd);
  1467. ///
  1468. /// WR_AddClipboardFunc
  1469. //  Adds contents of clipboard as attachment
  1470. SAVEDS ASM void WR_AddClipboardFunc(REG(a1) int *arg)
  1471. {
  1472.    int winnum = *arg;
  1473.    struct TempFile *tf = OpenTempFile("w");
  1474.    if (DumpClipboard(tf->FP))
  1475.    {
  1476.       fclose(tf->FP); tf->FP = NULL;
  1477.       WR_AddFileToList(winnum, tf->Filename, "clipboard.text", TRUE);
  1478.       free(tf);
  1479.       return;
  1480.    }
  1481.    CloseTempFile(tf);
  1482. }
  1483. MakeHook(WR_AddClipboardHook, WR_AddClipboardFunc);
  1484. ///
  1485. /// WR_AddPGPKeyFunc
  1486. //  Adds ASCII version of user's public PGP key as attachment
  1487. SAVEDS ASM void WR_AddPGPKeyFunc(REG(a1) int *arg)
  1488. {
  1489.    int winnum = *arg;
  1490.    char *myid = *C->MyPGPID ? C->MyPGPID : C->EmailAddress;
  1491.    char options[SIZE_LARGE], *fname = "T:PubKey.asc";
  1492.    sprintf(options, (G->PGPVersion == 5) ? "-x %s -o %s +force +batchmode=1" : "-kxa %s %s +f +bat", myid, fname);
  1493.    if (!PGPCommand((G->PGPVersion == 5) ? "pgpk" : "pgp", options, 0)) if (FileSize(fname) > 0)
  1494.    {
  1495.       WR_AddFileToList(winnum, fname, NULL, TRUE);
  1496.       setstring(G->WR[winnum]->GUI.ST_CTYPE, "application/pgp-keys");
  1497.    }
  1498.    else ER_NewError(GetStr(MSG_ER_ErrorAppendKey), myid, NULL);
  1499. }
  1500. MakeHook(WR_AddPGPKeyHook, WR_AddPGPKeyFunc);
  1501. ///
  1502.  
  1503. /*** Open ***/
  1504. /// WR_Open
  1505. //  Initializes a write window
  1506. int WR_Open(int winnum, BOOL bounce)
  1507. {
  1508.    if (winnum == -1) if (G->WR[winnum = 0]) if (G->WR[winnum = 1]) return -1;
  1509.    G->WR[winnum] = bounce ? WR_NewBounce(winnum) : WR_New(winnum);
  1510.    if (!G->WR[winnum]) return -1;
  1511.    if (!bounce)
  1512.    {
  1513.       struct WR_GUIData *gui = &G->WR[winnum]->GUI;
  1514.       setstring(gui->ST_FROM, BuildAddrName(C->EmailAddress, C->RealName));
  1515.       setstring(gui->ST_REPLYTO, C->ReplyTo);
  1516.       setstring(gui->ST_EXTHEADER, C->ExtraHeaders);
  1517.       setcheckmark(gui->CH_DELSEND, !C->SaveSent);
  1518.       setcheckmark(gui->CH_ADDINFO, C->AddMyInfo);
  1519.    }
  1520.    MA_StartMacro(MACRO_PREWRITE, itoa(winnum));
  1521.    return winnum;
  1522. }
  1523. ///
  1524. /// WR_SetupOldMail
  1525. //  When editing a message, sets write window options to old values
  1526. void WR_SetupOldMail(int winnum)
  1527. {
  1528.    static struct Attach attach;
  1529.    struct Part *part = G->RE[4]->FirstPart->Next;
  1530.  
  1531.    if (part) for (part = part->Next; part; part = part->Next)
  1532.       if (stricmp(part->ContentType, "application/pgp-signature"))
  1533.       {
  1534.          Busy(GetStr(MSG_BusyDecSaving), "", 0, 0);
  1535.          RE_DecodePart(part);
  1536.          clear(&attach, sizeof(struct Attach));
  1537.          attach.Size = part->Size;
  1538.          attach.IsMIME = part->EncodingCode != ENC_UUE;
  1539.          attach.IsTemp = TRUE;
  1540.          if (part->Name) stccpy(attach.Name, part->Name, SIZE_FILE);
  1541.          strcpy(attach.FilePath, part->Filename);
  1542.          *part->Filename = 0;
  1543.          stccpy(attach.ContentType, part->ContentType, SIZE_CTYPE);
  1544.          stccpy(attach.Description, part->Description, SIZE_DEFAULT);
  1545.          DoMethod(G->WR[winnum]->GUI.LV_ATTACH, MUIM_List_InsertSingle, &attach, MUIV_List_Insert_Bottom);
  1546.          BusyEnd;
  1547.       }
  1548. }
  1549. ///
  1550. /// WR_UpdateTitleFunc
  1551. //  Shows cursor coordinates
  1552. SAVEDS ASM void WR_UpdateWTitleFunc(REG(a1) int *arg)
  1553. {
  1554.    struct WR_ClassData *wr = G->WR[*arg];
  1555.    APTR ed = wr->GUI.TE_EDIT;
  1556.  
  1557.    sprintf(wr->WTitle, "%03ld\n%03ld", GetMUI(ed,MUIA_TextEditor_CursorY)+1, GetMUI(ed,MUIA_TextEditor_CursorX)+1);
  1558.    set(wr->GUI.TX_POSI, MUIA_Text_Contents, wr->WTitle);
  1559. }
  1560. MakeHook(WR_UpdateWTitleHook,WR_UpdateWTitleFunc);
  1561. ///
  1562.  
  1563. /*** Hooks ***/
  1564. /// WR_AppFunc
  1565. //  Handles Drag&Drop
  1566. void WR_App(int winnum, struct AppMessage *amsg)
  1567. {
  1568.    struct WBArg *ap;
  1569.    int i, mode;
  1570.    char buf[SIZE_PATHFILE];
  1571.  
  1572.    get(G->WR[winnum]->GUI.RG_PAGE, MUIA_Group_ActivePage, &mode);
  1573.    for (i = 0; i < amsg->am_NumArgs; i++)
  1574.    {
  1575.       ap = &amsg->am_ArgList[i];
  1576.       NameFromLock(ap->wa_Lock, buf, SIZE_PATHFILE);
  1577.       AddPart(buf, ap->wa_Name, SIZE_PATHFILE);
  1578.       if (!mode)
  1579.       {
  1580.          FILE *fh;
  1581.          int len, j, notascii = 0;
  1582.          char buffer[SIZE_LARGE];
  1583.          if (fh = fopen(buf, "r"))
  1584.          {
  1585.             len = fread(buffer, 1, SIZE_LARGE-1, fh);
  1586.             buffer[len] = 0;
  1587.             fclose(fh);
  1588.             for (j = 0; j < len; j++) if ((int)buffer[j] < 32 || (int)buffer[j] > 127) if (buffer[j] != '\t' && buffer[j] != '\n') notascii++;
  1589.             if (notascii) if (len/notascii <= 16) mode = 1;
  1590.          }
  1591.       }
  1592.       if (!mode)
  1593.       {
  1594.          char *text = WR_TransformText(buf, ED_INSERT, "");
  1595.          if (text) DoMethod(G->WR[winnum]->GUI.TE_EDIT, MUIM_TextEditor_InsertText, text);
  1596.          free(text);
  1597.       }
  1598.       else WR_AddFileToList(winnum, buf, NULL, FALSE);
  1599.    }
  1600. }
  1601. SAVEDS ASM LONG WR_AppFunc(REG(a1) ULONG *arg)
  1602. {
  1603.    WR_App((int)arg[1],  (struct AppMessage *)arg[0]);
  1604.    return 0;
  1605. }
  1606. MakeHook(WR_AppHook, WR_AppFunc);
  1607. ///
  1608. /// WR_LV_ConFunc
  1609. //  Attachment listview construct hook
  1610. SAVEDS ASM struct Attach *WR_LV_ConFunc(REG(a1) struct Attach *attach)
  1611. {
  1612.    struct Attach *entry = malloc(sizeof(struct Attach));
  1613.    *entry = *attach;
  1614.    return entry;
  1615. }
  1616. MakeHook(WR_LV_ConFuncHook, WR_LV_ConFunc);
  1617. ///
  1618. /// WR_LV_DspFunc
  1619. //  Attachment listview display hook
  1620. SAVEDS ASM long WR_LV_DspFunc(REG(a2) char **array, REG(a1) struct Attach *entry)
  1621. {
  1622.    static char dispsz[SIZE_SMALL];
  1623.    if (entry)
  1624.    {
  1625.       array[0] = entry->Name;
  1626.       sprintf(array[1] = dispsz, "%d", entry->Size);
  1627.       array[2] = DescribeCT(entry->ContentType);
  1628.       array[3] = entry->IsMIME ? "MIME" : "UU";
  1629.       array[4] = entry->Description;
  1630.    }
  1631.    else 
  1632.    {
  1633.       array[0] = GetStr(MSG_WR_TitleFile); 
  1634.       array[1] = GetStr(MSG_WR_TitleSize);
  1635.       array[2] = GetStr(MSG_WR_TitleContents);
  1636.       array[3] = GetStr(MSG_WR_TitleEncoding);
  1637.       array[4] = GetStr(MSG_WR_TitleDescription);
  1638.    }
  1639.    return 0;
  1640. }
  1641. MakeHook(WR_LV_DspFuncHook, WR_LV_DspFunc);
  1642. ///
  1643.  
  1644. /*** GUI ***/
  1645. /// WR_SharedSetup
  1646. //  Common setup for write and bounce windows
  1647. void WR_SharedSetup(struct WR_ClassData *data, int winnum)
  1648. {
  1649.    SetHelp(data->GUI.ST_TO      ,MSG_HELP_WR_ST_TO      );
  1650.    SetHelp(data->GUI.BT_QUEUE   ,MSG_HELP_WR_BT_QUEUE   );
  1651.    SetHelp(data->GUI.BT_HOLD    ,MSG_HELP_WR_BT_HOLD    );
  1652.    SetHelp(data->GUI.BT_SEND    ,MSG_HELP_WR_BT_SEND    );
  1653.    SetHelp(data->GUI.BT_CANCEL  ,MSG_HELP_WR_BT_CANCEL  );
  1654.    DoMethod(data->GUI.BT_HOLD    ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_NewMailHook,WRITE_HOLD,winnum);
  1655.    DoMethod(data->GUI.BT_QUEUE   ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_NewMailHook,WRITE_QUEUE,winnum);
  1656.    DoMethod(data->GUI.BT_SEND    ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_NewMailHook,WRITE_SEND,winnum);
  1657.    DoMethod(data->GUI.BT_CANCEL  ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_CancelHook,winnum);
  1658.    DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_CloseRequest ,TRUE          ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_CancelHook,winnum);
  1659. }
  1660. ///
  1661. /// MakeAddressField
  1662. //  Creates a recipient field
  1663. APTR MakeAddressField(APTR *string, char *label, APTR help, int abmode, int winnum, BOOL allowmulti)
  1664. {
  1665.    APTR obj, bt_ver, bt_adr;
  1666.    if (obj = HGroup,
  1667.       GroupSpacing(1),
  1668.       Child, *string = NewObject(CL_DDString->mcc_Class, NULL,
  1669.          MUIA_ControlChar, ShortCut(label),
  1670.          MUIA_UserData, allowmulti,
  1671.       End,
  1672.       Child, bt_ver = PopButton(MUII_ArrowLeft),
  1673.       Child, bt_adr = PopButton(MUII_PopUp),
  1674.    End)
  1675.    {
  1676.       set(bt_ver, MUIA_CycleChain, TRUE);
  1677.       set(bt_adr, MUIA_CycleChain, TRUE);
  1678.       SetHelp(*string,help);
  1679.       SetHelp(bt_ver, MSG_HELP_WR_BT_VER);
  1680.       SetHelp(bt_adr, MSG_HELP_WR_BT_ADR);
  1681.       DoMethod(*string,MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,MUIV_Notify_Window,5,MUIM_CallHook,&WR_VerifyAutoHook,*string,winnum,!allowmulti);
  1682.       DoMethod(bt_ver,MUIM_Notify,MUIA_Pressed,FALSE,MUIV_Notify_Application,5,MUIM_CallHook,&WR_VerifyManualHook,*string,winnum,!allowmulti);
  1683.       DoMethod(bt_adr,MUIM_Notify,MUIA_Pressed,FALSE,MUIV_Notify_Application,4,MUIM_CallHook,&AB_OpenHook,abmode,winnum);
  1684.    }
  1685.    return obj;
  1686. }
  1687. ///
  1688. /// WR_New
  1689. //  Creates a write window
  1690. enum { WMEN_NEW=1,WMEN_OPEN,WMEN_INSFILE,WMEN_SAVEAS,WMEN_INSQUOT,
  1691.        WMEN_INSROT13,WMEN_EDIT,WMEN_CUT,WMEN_COPY,WMEN_PASTE,
  1692.        WMEN_PASQUOT,WMEN_PASROT13,WMEN_DICT,WMEN_STYLE1,WMEN_STYLE2,WMEN_STYLE3,
  1693.        WMEN_STYLE4,WMEN_EMOT0,WMEN_EMOT1,WMEN_EMOT2,WMEN_EMOT3,WMEN_UNDO,WMEN_REDO,
  1694.        WMEN_AUTOSP,WMEN_SEP0,WMEN_SEP1,WMEN_ADDFILE, WMEN_ADDCLIP, WMEN_ADDPGP,
  1695.        WMEN_DELSEND,WMEN_RECEIPT,WMEN_DISPNOTI,WMEN_ADDINFO,WMEN_IMPORT0,WMEN_IMPORT1,
  1696.        WMEN_IMPORT2,WMEN_SIGN0,WMEN_SIGN1,WMEN_SIGN2,WMEN_SIGN3,
  1697.        WMEN_SECUR0,WMEN_SECUR1,WMEN_SECUR2,WMEN_SECUR3,WMEN_SECUR4 };
  1698. extern long cmap[8];
  1699.  
  1700. struct WR_ClassData *WR_New(int winnum)
  1701. {
  1702.    struct WR_ClassData *data;
  1703.  
  1704.    if (data = calloc(1,sizeof(struct WR_ClassData)))
  1705.    {
  1706.       static char *rtitles[4], *encoding[3], *security[6], *priority[4], *signat[5];
  1707.       static char *emoticons[4] = { ":-)", ":-|", ":-(", ";-)" };
  1708.       APTR mi_copy, mi_cut, mi_redo, mi_undo, mi_bold, mi_italic, mi_underl, mi_color;
  1709.       APTR strip, mi_autospell, mi_delsend, mi_receipt, mi_dispnoti, mi_addinfo;
  1710.       APTR slider = ScrollbarObject, End;
  1711.       APTR tb_butt[13] = { MSG_WR_TBEditor,MSG_WR_TBInsert,MSG_Space,
  1712.                            MSG_WR_TBCut,MSG_WR_TBCopy,MSG_WR_TBPaste,MSG_WR_TBUndo,MSG_Space,
  1713.                            MSG_WR_TBBold,MSG_WR_TBItalic,MSG_WR_TBUnderlined,MSG_WR_TBColored,NULL };
  1714.       APTR tb_help[13] = { MSG_HELP_WR_BT_EDITOR,MSG_HELP_WR_BT_LOAD,NULL,
  1715.                            MSG_HELP_WR_BT_CUT,MSG_HELP_WR_BT_COPY,MSG_HELP_WR_BT_PASTE,MSG_HELP_WR_BT_UNDO,NULL,
  1716.                            MSG_HELP_WR_BT_BOLD,MSG_HELP_WR_BT_ITALIC,MSG_HELP_WR_BT_UNDERL,MSG_HELP_WR_BT_COLOR,NULL };
  1717.       int i, spell;
  1718.       for (i = 0; i < 13; i++) SetupToolbar(&(data->GUI.TB_TOOLBAR[i]), tb_butt[i]?(tb_butt[i]==MSG_Space?"":GetStr(tb_butt[i])):NULL, tb_help[i]?GetStr(tb_help[i]):NULL, (i>=8 && i<=11)?TDF_TOGGLE:0);
  1719.       rtitles[0] = GetStr(MSG_Message);
  1720.       rtitles[1] = GetStr(MSG_Attachments);
  1721.       rtitles[2] = GetStr(MSG_Options);
  1722.       rtitles[3] = NULL;
  1723.       encoding[0] = "Base64/QP";
  1724.       encoding[1] = "UUencode";
  1725.       encoding[2] = NULL;
  1726.       security[0] = GetStr(MSG_WR_SecNone);
  1727.       security[1] = GetStr(MSG_WR_SecSign);
  1728.       security[2] = GetStr(MSG_WR_SecEncrypt);
  1729.       security[3] = GetStr(MSG_WR_SecBoth);
  1730.       security[4] = GetStr(MSG_WR_SecAnon);
  1731.       security[5] = NULL;
  1732.       priority[0] = GetStr(MSG_WR_ImpHigh);
  1733.       priority[1] = GetStr(MSG_WR_ImpNormal);
  1734.       priority[2] = GetStr(MSG_WR_ImpLow);
  1735.       priority[3] = NULL;
  1736.       signat[0] = GetStr(MSG_WR_NoSig);
  1737.       signat[1] = GetStr(MSG_WR_DefSig);
  1738.       signat[2] = GetStr(MSG_WR_AltSig1);
  1739.       signat[3] = GetStr(MSG_WR_AltSig2);
  1740.       signat[4] = NULL;
  1741.       data->GUI.WI = WindowObject,
  1742.          MUIA_Window_Title, GetStr(MSG_WR_WriteWT),
  1743.          MUIA_HelpNode, "WR_W",
  1744.          MUIA_Window_ID, MAKE_ID('W','R','I','T'),
  1745.          MUIA_Window_Menustrip, strip = MenustripObject,
  1746.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_WR_Text),
  1747.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_New), MUIA_Menuitem_Shortcut,"N", MUIA_UserData,WMEN_NEW, End,
  1748.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_Open), MUIA_Menuitem_Shortcut,"O", MUIA_UserData,WMEN_OPEN, End,
  1749.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_InsertAs),
  1750.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Plain), MUIA_Menuitem_Shortcut,"P", MUIA_UserData,WMEN_INSFILE, End,
  1751.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Quoted), MUIA_UserData,WMEN_INSQUOT, End,
  1752.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_ROT13), MUIA_UserData,WMEN_INSROT13, End,
  1753.                End,
  1754.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,(char)NM_BARLABEL, End,
  1755.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_SaveAs), MUIA_UserData,WMEN_SAVEAS, End,
  1756.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,(char)NM_BARLABEL, End,
  1757.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_LaunchEd), MUIA_Menuitem_Shortcut,"E", MUIA_UserData,WMEN_EDIT, End,
  1758.             End,
  1759.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_WR_Edit),
  1760.                MUIA_Family_Child, mi_cut = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MCut), MUIA_Menuitem_Shortcut,"ramiga X", MUIA_Menuitem_CommandString,TRUE, MUIA_UserData,WMEN_CUT, End,
  1761.                MUIA_Family_Child, mi_copy = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MCopy), MUIA_Menuitem_Shortcut,"ramiga C", MUIA_Menuitem_CommandString,TRUE, MUIA_UserData,WMEN_COPY, End,
  1762.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MPaste), MUIA_Menuitem_Shortcut,"ramiga V", MUIA_Menuitem_CommandString,TRUE, MUIA_UserData,WMEN_PASTE, End,
  1763.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_PasteAs),
  1764.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Quoted), MUIA_Menuitem_Shortcut,"Q", MUIA_UserData,WMEN_PASQUOT, End,
  1765.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_ROT13), MUIA_UserData,WMEN_PASROT13, End,
  1766.                End,
  1767.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,(char)NM_BARLABEL, End,
  1768.                MUIA_Family_Child, mi_undo = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MUndo), MUIA_Menuitem_Shortcut,"ramiga Z", MUIA_Menuitem_CommandString,TRUE, MUIA_UserData,WMEN_UNDO, End,
  1769.                MUIA_Family_Child, mi_redo = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Redo), WMEN_REDO, End,
  1770.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,(char)NM_BARLABEL, End,
  1771.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Dictionary), MUIA_Menuitem_Shortcut,"D", MUIA_UserData,WMEN_DICT, End,
  1772.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Textstyle),
  1773.                   MUIA_Family_Child, mi_bold = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Bold), MUIA_Menuitem_Shortcut,"B", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_STYLE1, End,
  1774.                   MUIA_Family_Child, mi_italic = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Italic), MUIA_Menuitem_Shortcut,"I", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_STYLE2, End,
  1775.                   MUIA_Family_Child, mi_underl = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Underlined), MUIA_Menuitem_Shortcut,"U", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_STYLE3, End,
  1776.                   MUIA_Family_Child, mi_color = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Colored), MUIA_Menuitem_Shortcut,"A", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_STYLE4, End,
  1777.                End,
  1778.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Separators),
  1779.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title, GetStr(MSG_WR_Thin), MUIA_Menuitem_Shortcut,"-", MUIA_UserData,WMEN_SEP0, End,
  1780.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title, GetStr(MSG_WR_Thick), MUIA_Menuitem_Shortcut,"=", MUIA_UserData,WMEN_SEP1, End,
  1781.                End,
  1782.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Emoticons),
  1783.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Happy), MUIA_UserData,WMEN_EMOT0, End,
  1784.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Indifferent), MUIA_UserData,WMEN_EMOT1, End,
  1785.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Sad), MUIA_UserData,WMEN_EMOT2, End,
  1786.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_Ironic), MUIA_UserData,WMEN_EMOT3, End,
  1787.                End,
  1788.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,(char)NM_BARLABEL, End,
  1789.                MUIA_Family_Child, mi_autospell = MenuitemObject, MUIA_Menuitem_Title, GetStr(MSG_WR_SpellCheck), MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_AUTOSP, End,
  1790.             End,
  1791.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_Attachments),
  1792.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MAddFile), MUIA_Menuitem_Shortcut,"F", MUIA_UserData,WMEN_ADDFILE, End,
  1793.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_AddCB), MUIA_UserData,WMEN_ADDCLIP, End,
  1794.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_AddKey), MUIA_UserData,WMEN_ADDPGP, End,
  1795.             End,
  1796.             MUIA_Family_Child, MenuObject, MUIA_Menu_Title, GetStr(MSG_Options),
  1797.                MUIA_Family_Child, mi_delsend = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MDelSend), MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_DELSEND, End,
  1798.                MUIA_Family_Child, mi_receipt = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MReceipt), MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_RECEIPT, End,
  1799.                MUIA_Family_Child, mi_dispnoti= MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MGetMDN),  MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_DISPNOTI, End,
  1800.                MUIA_Family_Child, mi_addinfo = MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MAddInfo), MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Toggle,TRUE, MUIA_UserData,WMEN_ADDINFO, End,
  1801.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_WR_MImportance),
  1802.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,priority[0], MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x06, MUIA_UserData,WMEN_IMPORT0, End,
  1803.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,priority[1], MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x05, MUIA_Menuitem_Checked,TRUE, MUIA_UserData,WMEN_IMPORT1, End,
  1804.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,priority[2], MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x03, MUIA_UserData,WMEN_IMPORT2, End,
  1805.                End,
  1806.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_CO_CrdSignature),
  1807.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,signat[0], MUIA_Menuitem_Shortcut,"0", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x0E, MUIA_Menuitem_Checked,!C->UseSignature, MUIA_UserData,WMEN_SIGN0, End,
  1808.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,signat[1], MUIA_Menuitem_Shortcut,"7", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x0D, MUIA_Menuitem_Checked,C->UseSignature, MUIA_UserData,WMEN_SIGN1, End,
  1809.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,signat[2], MUIA_Menuitem_Shortcut,"8", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x0B, MUIA_UserData,WMEN_SIGN2, End,
  1810.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,signat[3], MUIA_Menuitem_Shortcut,"9", MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x07, MUIA_UserData,WMEN_SIGN3, End,
  1811.                End,
  1812.                MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,GetStr(MSG_CO_CrdSecurity),
  1813.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,security[0], MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x1E, MUIA_Menuitem_Checked,TRUE, MUIA_UserData,WMEN_SECUR0, End,
  1814.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,security[1], MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x1D, MUIA_UserData,WMEN_SECUR1, End,
  1815.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,security[2], MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x1B, MUIA_UserData,WMEN_SECUR2, End,
  1816.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,security[3], MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x17, MUIA_UserData,WMEN_SECUR3, End,
  1817.                   MUIA_Family_Child, MenuitemObject, MUIA_Menuitem_Title,security[4], MUIA_Menuitem_Checkit,TRUE, MUIA_Menuitem_Exclude,0x0F, MUIA_UserData,WMEN_SECUR4, End,
  1818.                End,
  1819.             End,
  1820.          End,
  1821.          MUIA_Window_AppWindow, TRUE,
  1822.          WindowContents, VGroup,
  1823.             Child, data->GUI.RG_PAGE = RegisterGroup(rtitles),
  1824.                MUIA_CycleChain, 1,
  1825.                Child, VGroup, /* Message */
  1826.                   MUIA_HelpNode, "WR00",
  1827.                   Child, ColGroup(2),
  1828.                      Child, Label(GetStr(MSG_WR_To)),
  1829.                      Child, MakeAddressField(&data->GUI.ST_TO, GetStr(MSG_WR_To), MSG_HELP_WR_ST_TO, ABM_TO, winnum, TRUE),
  1830.                      Child, Label(GetStr(MSG_WR_Subject)),
  1831.                      Child, data->GUI.ST_SUBJECT = MakeString(SIZE_SUBJECT,GetStr(MSG_WR_Subject)),
  1832.                   End,
  1833.                   Child, (C->HideGUIElements & HIDE_TBAR) ?
  1834.                      (RectangleObject, MUIA_ShowMe, FALSE, End) :
  1835.                      (HGroup, GroupSpacing(0),
  1836.                         Child, HGroupV,
  1837.                            Child, data->GUI.TO_TOOLBAR = ToolbarObject,
  1838.                               MUIA_Toolbar_ImageType,      MUIV_Toolbar_ImageType_File,
  1839.                               MUIA_Toolbar_ImageNormal,    "PROGDIR:Icons/Write.toolbar",
  1840.                               MUIA_Toolbar_ImageGhost,     "PROGDIR:Icons/Write_G.toolbar",
  1841.                               MUIA_Toolbar_ImageSelect,    "PROGDIR:Icons/Write_S.toolbar",
  1842.                               MUIA_Toolbar_Description,    data->GUI.TB_TOOLBAR,
  1843.                               MUIA_Font,                   MUIV_Font_Tiny,
  1844.                               MUIA_ShortHelp, TRUE,
  1845.                            End,
  1846.                            Child, HSpace(0),
  1847.                         End,
  1848.                         Child, (C->HideGUIElements & HIDE_XY) ?
  1849.                            HSpace(1) :
  1850.                            (VCenter((data->GUI.TX_POSI = TextObject,
  1851.                               TextFrame,
  1852.                               MUIA_Weight    ,0,
  1853.                               MUIA_Text_Contents, "000\n000",
  1854.                               MUIA_Background,MUII_TextBack,
  1855.                               MUIA_Frame     ,MUIV_Frame_Text,
  1856.                               MUIA_Font      ,MUIV_Font_Tiny,
  1857.                            End))),
  1858.                      End),
  1859.                   Child, HGroup,
  1860.                      MUIA_HelpNode, "EDIT",
  1861.                      MUIA_Group_Spacing, 0,
  1862.                      Child, data->GUI.TE_EDIT = NewObject(CL_TextEditor->mcc_Class,NULL,
  1863.                         InputListFrame,
  1864.                         MUIA_TextEditor_Slider, slider,
  1865.                         MUIA_TextEditor_ColorMap, G->EdColMap,
  1866.                         MUIA_TextEditor_FixedFont, C->FixedFontEdit,
  1867.                         MUIA_TextEditor_WrapBorder, C->EdWrapMode == 1 ? C->EdWrapCol : 0,
  1868.                         MUIA_TextEditor_ExportWrap, C->EdWrapMode == 2 ? C->EdWrapCol : 0,
  1869.                         MUIA_TextEditor_ImportHook, MUIV_TextEditor_ImportHook_EMail,
  1870.                         MUIA_TextEditor_ExportHook, MUIV_TextEditor_ExportHook_EMail,
  1871.                         MUIA_CycleChain, TRUE,
  1872.                      End,
  1873.                      Child, slider,
  1874.                   End,
  1875.                End,
  1876.                Child, VGroup, /* Attachments */
  1877.                   MUIA_HelpNode, "WR01",
  1878.                   Child, ListviewObject,
  1879.                      MUIA_CycleChain, 1,
  1880.                      MUIA_Listview_DragType, 1,
  1881.                      MUIA_Listview_List,data->GUI.LV_ATTACH = NewObject(CL_AttachList->mcc_Class,NULL,
  1882.                         InputListFrame,
  1883.                         MUIA_List_DragSortable ,TRUE,
  1884.                         MUIA_List_Format       ,"D=8 BAR,P=\033r D=8 BAR,D=8 BAR,P=\033c D=8 BAR,",
  1885.                         MUIA_List_Title        ,TRUE,
  1886.                         MUIA_List_ConstructHook,&WR_LV_ConFuncHook,
  1887.                         MUIA_List_DestructHook ,&GeneralDesHook,
  1888.                         MUIA_List_DisplayHook  ,&WR_LV_DspFuncHook, 
  1889.                      End,
  1890.                   End,
  1891.                   Child, ColGroup(4),
  1892.                      Child, data->GUI.BT_ADD     = MakeButton(GetStr(MSG_WR_Add)),
  1893.                      Child, data->GUI.BT_ADDPACK = MakeButton(GetStr(MSG_WR_AddPack)),
  1894.                      Child, data->GUI.BT_DEL     = MakeButton(GetStr(MSG_Del)),
  1895.                      Child, data->GUI.BT_DISPLAY = MakeButton(GetStr(MSG_WR_Display)),
  1896.                   End,
  1897.                   Child, HGroup,
  1898.                      Child, data->GUI.RA_ENCODING = RadioObject,
  1899.                         GroupFrameT(GetStr(MSG_WR_Encoding)),
  1900.                         MUIA_Radio_Entries, encoding,
  1901.                         MUIA_CycleChain, 1,
  1902.                      End,
  1903.                      Child, ColGroup(2),
  1904.                         Child, Label2(GetStr(MSG_WR_ContentType)),
  1905.                         Child, PoplistObject,
  1906.                            MUIA_Popstring_String, data->GUI.ST_CTYPE = MakeString(SIZE_CTYPE,GetStr(MSG_WR_ContentType)),
  1907.                            MUIA_Popstring_Button, PopButton(MUII_PopUp),
  1908.                            MUIA_Poplist_Array   , ContType,
  1909.                         End,
  1910.                         Child, Label2(GetStr(MSG_WR_Description)),
  1911.                         Child, data->GUI.ST_DESC = MakeString(SIZE_DEFAULT,GetStr(MSG_WR_Description)),
  1912.                         Child, HSpace(0),
  1913.                      End,
  1914.                   End,
  1915.                End,
  1916.                Child, VGroup, /* Options */
  1917.                   MUIA_HelpNode, "WR02",
  1918.                   Child, ColGroup(2),
  1919.                      Child, Label(GetStr(MSG_WR_CopyTo)),
  1920.                      Child, MakeAddressField(&data->GUI.ST_CC, GetStr(MSG_WR_CopyTo), MSG_HELP_WR_ST_CC, ABM_CC, winnum, TRUE),
  1921.                      Child, Label(GetStr(MSG_WR_BlindCopyTo)),
  1922.                      Child, MakeAddressField(&data->GUI.ST_BCC, GetStr(MSG_WR_BlindCopyTo), MSG_HELP_WR_ST_BCC, ABM_BCC, winnum, TRUE),
  1923.                      Child, Label(GetStr(MSG_WR_From)),
  1924.                      Child, MakeAddressField(&data->GUI.ST_FROM, GetStr(MSG_WR_From), MSG_HELP_WR_ST_FROM, ABM_FROM, winnum, FALSE),
  1925.                      Child, Label(GetStr(MSG_WR_ReplyTo)),
  1926.                      Child, MakeAddressField(&data->GUI.ST_REPLYTO, GetStr(MSG_WR_ReplyTo), MSG_HELP_WR_ST_REPLYTO, ABM_REPLYTO, winnum, FALSE),
  1927.                      Child, Label(GetStr(MSG_WR_ExtraHeaders)),
  1928.                      Child, data->GUI.ST_EXTHEADER = MakeString(SIZE_LARGE,GetStr(MSG_WR_ExtraHeaders)),
  1929.                   End,
  1930.                   Child, HGroup,
  1931.                      Child, VGroup, GroupFrameT(GetStr(MSG_WR_SendOpt)),
  1932.                         Child, MakeCheckGroup((Object **)&data->GUI.CH_DELSEND, GetStr(MSG_WR_DelSend)),
  1933.                         Child, MakeCheckGroup((Object **)&data->GUI.CH_RECEIPT, GetStr(MSG_WR_Receipt)),
  1934.                         Child, MakeCheckGroup((Object **)&data->GUI.CH_DISPNOTI, GetStr(MSG_WR_GetMDN)),
  1935.                         Child, MakeCheckGroup((Object **)&data->GUI.CH_ADDINFO, GetStr(MSG_WR_AddInfo)),
  1936.                         Child, HGroup,
  1937.                            Child, Label(GetStr(MSG_WR_Importance)),
  1938.                            Child, data->GUI.CY_IMPORTANCE = MakeCycle(priority, GetStr(MSG_WR_Importance)),
  1939.                         End,
  1940.                      End,
  1941.                      Child, HSpace(0),
  1942.                      Child, data->GUI.RA_SIGNATURE = RadioObject, GroupFrameT(GetStr(MSG_WR_Signature)),
  1943.                         MUIA_Radio_Entries, signat,
  1944.                         MUIA_Radio_Active, C->UseSignature ? 1 : 0,
  1945.                         MUIA_CycleChain, 1,
  1946.                      End,
  1947.                      Child, HSpace(0),
  1948.                      Child, data->GUI.RA_SECURITY = RadioObject, GroupFrameT(GetStr(MSG_WR_Security)),
  1949.                         MUIA_Radio_Entries, security,
  1950.                         MUIA_CycleChain, 1,
  1951.                      End,
  1952.                   End,
  1953.                End,
  1954.             End,
  1955.             Child, ColGroup(4),
  1956.                Child, data->GUI.BT_SEND   = MakeButton(GetStr(MSG_WR_Send)),
  1957.                Child, data->GUI.BT_QUEUE  = MakeButton(GetStr(MSG_WR_ToQueue)),
  1958.                Child, data->GUI.BT_HOLD   = MakeButton(GetStr(MSG_WR_Hold)),
  1959.                Child, data->GUI.BT_CANCEL = MakeButton(GetStr(MSG_Cancel)),
  1960.             End,
  1961.          End,
  1962.       End;
  1963.       if (data->GUI.WI)
  1964.       {
  1965.          DoMethod(G->App, OM_ADDMEMBER, data->GUI.WI);
  1966.          set(data->GUI.ST_TO, MUIA_UserData, data->GUI.ST_SUBJECT);
  1967.          set(data->GUI.ST_CC, MUIA_UserData, data->GUI.ST_BCC);
  1968.          set(data->GUI.ST_BCC, MUIA_UserData, data->GUI.ST_FROM);
  1969.          set(data->GUI.ST_FROM, MUIA_UserData, data->GUI.ST_REPLYTO);
  1970.          set(data->GUI.ST_REPLYTO, MUIA_UserData, data->GUI.ST_EXTHEADER);
  1971.          get(data->GUI.TE_EDIT, MUIA_TextEditor_TypeAndSpell, &spell);
  1972.          set(mi_autospell, MUIA_Menuitem_Checked, spell);
  1973.          set(data->GUI.CY_IMPORTANCE, MUIA_Cycle_Active, 1);
  1974.          DoMethod(G->App, MUIM_MultiSet, MUIA_Disabled, TRUE, data->GUI.RA_ENCODING, data->GUI.ST_CTYPE, data->GUI.ST_DESC, data->GUI.BT_DEL, data->GUI.BT_DISPLAY, NULL);
  1975.          SetHelp(data->GUI.ST_SUBJECT   ,MSG_HELP_WR_ST_SUBJECT   );
  1976.          SetHelp(data->GUI.BT_ADD       ,MSG_HELP_WR_BT_ADD       );
  1977.          SetHelp(data->GUI.BT_ADDPACK   ,MSG_HELP_WR_BT_ADDPACK   );
  1978.          SetHelp(data->GUI.BT_DEL       ,MSG_HELP_WR_BT_DEL       );
  1979.          SetHelp(data->GUI.BT_DISPLAY   ,MSG_HELP_WR_BT_DISPLAY   );
  1980.          SetHelp(data->GUI.RA_ENCODING  ,MSG_HELP_WR_RA_ENCODING  );
  1981.          SetHelp(data->GUI.ST_CTYPE     ,MSG_HELP_WR_ST_CTYPE     );
  1982.          SetHelp(data->GUI.ST_DESC      ,MSG_HELP_WR_ST_DESC      );
  1983.          SetHelp(data->GUI.ST_EXTHEADER ,MSG_HELP_WR_ST_EXTHEADER );
  1984.          SetHelp(data->GUI.CH_DELSEND   ,MSG_HELP_WR_CH_DELSEND   );
  1985.          SetHelp(data->GUI.CH_RECEIPT   ,MSG_HELP_WR_CH_RECEIPT   );
  1986.          SetHelp(data->GUI.CH_DISPNOTI  ,MSG_HELP_WR_CH_DISPNOTI  );
  1987.          SetHelp(data->GUI.CH_ADDINFO   ,MSG_HELP_WR_CH_ADDINFO   );
  1988.          SetHelp(data->GUI.CY_IMPORTANCE,MSG_HELP_WR_CY_IMPORTANCE);
  1989.          SetHelp(data->GUI.RA_SIGNATURE ,MSG_HELP_WR_RA_SIGNATURE );
  1990.          SetHelp(data->GUI.RA_SECURITY  ,MSG_HELP_WR_RA_SECURITY  );
  1991.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_NEW      ,data->GUI.TE_EDIT      ,1,MUIM_TextEditor_ClearText);
  1992.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_OPEN     ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_EditorCmdHook,ED_OPEN,winnum);
  1993.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_INSFILE  ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_EditorCmdHook,ED_INSERT,winnum);
  1994.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_INSQUOT  ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_EditorCmdHook,ED_INSQUOT,winnum);
  1995.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_INSROT13 ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_EditorCmdHook,ED_INSROT13,winnum);
  1996.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_SAVEAS   ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_SaveAsHook,winnum);
  1997.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_EDIT     ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_EditHook,winnum);
  1998.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_CUT      ,data->GUI.TE_EDIT      ,3,MUIM_TextEditor_ARexxCmd,"Cut");
  1999.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_COPY     ,data->GUI.TE_EDIT      ,3,MUIM_TextEditor_ARexxCmd,"Copy");
  2000.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_PASTE    ,data->GUI.TE_EDIT      ,3,MUIM_TextEditor_ARexxCmd,"Paste");
  2001.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_PASQUOT  ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_EditorCmdHook,ED_PASQUOT,winnum);
  2002.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_PASROT13 ,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_EditorCmdHook,ED_PASROT13,winnum);
  2003.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_DICT     ,MUIV_Notify_Application,3,MUIM_CallHook   ,&DI_OpenHook,winnum);
  2004.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_UNDO     ,data->GUI.TE_EDIT      ,3,MUIM_TextEditor_ARexxCmd,"Undo");
  2005.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_REDO     ,data->GUI.TE_EDIT      ,3,MUIM_TextEditor_ARexxCmd,"Redo");
  2006.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_ADDFILE  ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_AddFileHook,winnum);
  2007.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_ADDCLIP  ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_AddClipboardHook,winnum);
  2008.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_ADDPGP   ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_AddPGPKeyHook,winnum);
  2009.          for (i = 0; i < 4; i++) DoMethod(data->GUI.WI,MUIM_Notify,MUIA_Window_MenuAction,WMEN_EMOT0+i,data->GUI.TE_EDIT,2,MUIM_TextEditor_InsertText,emoticons[i]);
  2010.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_SEP0     ,data->GUI.TE_EDIT      ,4,MUIM_CallHook   ,&WR_InsertSeparatorHook,FALSE,winnum);
  2011.          DoMethod(data->GUI.WI         ,MUIM_Notify,MUIA_Window_MenuAction   ,WMEN_SEP1     ,data->GUI.TE_EDIT      ,4,MUIM_CallHook   ,&WR_InsertSeparatorHook,TRUE,winnum);
  2012.          DoMethod(data->GUI.RG_PAGE    ,MUIM_Notify,MUIA_AppMessage          ,MUIV_EveryTime,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_AppHook,MUIV_TriggerValue,winnum);
  2013.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify,MUIA_TextEditor_AreaMarked,MUIV_EveryTime,MUIV_Notify_Application,5,MUIM_MultiSet  ,MUIA_Menuitem_Enabled,MUIV_TriggerValue,mi_copy,mi_cut,NULL);
  2014.          if (data->GUI.TO_TOOLBAR)
  2015.          {
  2016.             DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify,MUIA_TextEditor_AreaMarked,MUIV_EveryTime,data->GUI.TO_TOOLBAR  ,6,MUIM_Toolbar_MultiSet,MUIV_Toolbar_Set_Ghosted, MUIV_NotTriggerValue,3,4,-1);
  2017.             DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify,MUIA_TextEditor_UndoAvailable,MUIV_EveryTime,data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set,6,MUIV_Toolbar_Set_Ghosted,MUIV_NotTriggerValue);
  2018.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 0, MUIV_Toolbar_Notify_Pressed,FALSE, MUIV_Notify_Application,3,MUIM_CallHook,&WR_EditHook,winnum);
  2019.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 1, MUIV_Toolbar_Notify_Pressed,FALSE, MUIV_Notify_Application,4,MUIM_CallHook,&WR_EditorCmdHook,ED_INSERT,winnum);
  2020.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 3, MUIV_Toolbar_Notify_Pressed,FALSE, data->GUI.TE_EDIT,2,MUIM_TextEditor_ARexxCmd, "CUT");
  2021.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 4, MUIV_Toolbar_Notify_Pressed,FALSE, data->GUI.TE_EDIT,2,MUIM_TextEditor_ARexxCmd, "COPY");
  2022.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 5, MUIV_Toolbar_Notify_Pressed,FALSE, data->GUI.TE_EDIT,2,MUIM_TextEditor_ARexxCmd, "PASTE");
  2023.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 6, MUIV_Toolbar_Notify_Pressed,FALSE, data->GUI.TE_EDIT,2,MUIM_TextEditor_ARexxCmd, "UNDO");
  2024.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 8, MUIV_Toolbar_Notify_Pressed,MUIV_EveryTime, data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_StyleBold,     MUIV_TriggerValue);
  2025.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify, 9, MUIV_Toolbar_Notify_Pressed,MUIV_EveryTime, data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_StyleItalic,   MUIV_TriggerValue);
  2026.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify,10, MUIV_Toolbar_Notify_Pressed,MUIV_EveryTime, data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_StyleUnderline,MUIV_TriggerValue);
  2027.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify,11, MUIV_Toolbar_Notify_Pressed,TRUE,           data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_Pen,           7);
  2028.             DoMethod(data->GUI.TO_TOOLBAR ,MUIM_Toolbar_Notify,11, MUIV_Toolbar_Notify_Pressed,FALSE,          data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_Pen,           0);
  2029.             DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_StyleBold,      MUIV_EveryTime, data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set, 8,MUIV_Toolbar_Set_Selected,MUIV_TriggerValue);
  2030.             DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_StyleItalic,    MUIV_EveryTime, data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set, 9,MUIV_Toolbar_Set_Selected,MUIV_TriggerValue);
  2031.             DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_StyleUnderline, MUIV_EveryTime, data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set,10,MUIV_Toolbar_Set_Selected,MUIV_TriggerValue);
  2032.             DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_Pen,            7,              data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set,11,MUIV_Toolbar_Set_Selected,TRUE);
  2033.             DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_Pen,            0,              data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set,11,MUIV_Toolbar_Set_Selected,FALSE);
  2034.             DoMethod(mi_bold              ,MUIM_Notify, MUIA_Menuitem_Checked,          MUIV_EveryTime, data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set, 8,MUIV_Toolbar_Set_Selected,MUIV_TriggerValue);
  2035.             DoMethod(mi_italic            ,MUIM_Notify, MUIA_Menuitem_Checked,          MUIV_EveryTime, data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set, 9,MUIV_Toolbar_Set_Selected,MUIV_TriggerValue);
  2036.             DoMethod(mi_underl            ,MUIM_Notify, MUIA_Menuitem_Checked,          MUIV_EveryTime, data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set,10,MUIV_Toolbar_Set_Selected,MUIV_TriggerValue);
  2037.             DoMethod(mi_color             ,MUIM_Notify, MUIA_Menuitem_Checked,          MUIV_EveryTime, data->GUI.TO_TOOLBAR,4,MUIM_Toolbar_Set,11,MUIV_Toolbar_Set_Selected,MUIV_TriggerValue);
  2038.          }
  2039.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify,MUIA_TextEditor_UndoAvailable,MUIV_EveryTime,mi_undo            ,3,MUIM_Set,MUIA_Menuitem_Enabled,MUIV_TriggerValue);
  2040.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify,MUIA_TextEditor_RedoAvailable,MUIV_EveryTime,mi_redo            ,3,MUIM_Set,MUIA_Menuitem_Enabled,MUIV_TriggerValue);
  2041.          if (data->GUI.TX_POSI)
  2042.          {
  2043.             DoMethod(data->GUI.TE_EDIT ,MUIM_Notify,MUIA_TextEditor_CursorX,MUIV_EveryTime,MUIV_Notify_Application,3,MUIM_CallHook,&WR_UpdateWTitleHook,winnum);
  2044.             DoMethod(data->GUI.TE_EDIT ,MUIM_Notify,MUIA_TextEditor_CursorY,MUIV_EveryTime,MUIV_Notify_Application,3,MUIM_CallHook,&WR_UpdateWTitleHook,winnum);
  2045.          }
  2046.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_StyleBold,      MUIV_EveryTime, mi_bold        ,3,MUIM_Set        ,MUIA_Menuitem_Checked,MUIV_TriggerValue);
  2047.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_StyleItalic,    MUIV_EveryTime, mi_italic      ,3,MUIM_Set        ,MUIA_Menuitem_Checked,MUIV_TriggerValue);
  2048.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_StyleUnderline, MUIV_EveryTime, mi_underl      ,3,MUIM_Set        ,MUIA_Menuitem_Checked,MUIV_TriggerValue);
  2049.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_Pen,            7,              mi_color       ,3,MUIM_Set        ,MUIA_Menuitem_Checked,TRUE);
  2050.          DoMethod(data->GUI.TE_EDIT    ,MUIM_Notify, MUIA_TextEditor_Pen,            0,              mi_color       ,3,MUIM_Set        ,MUIA_Menuitem_Checked,FALSE);
  2051.          DoMethod(mi_bold              ,MUIM_Notify, MUIA_Menuitem_Checked,          MUIV_EveryTime, data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_StyleBold,     MUIV_TriggerValue);
  2052.          DoMethod(mi_italic            ,MUIM_Notify, MUIA_Menuitem_Checked,          MUIV_EveryTime, data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_StyleItalic,   MUIV_TriggerValue);
  2053.          DoMethod(mi_underl            ,MUIM_Notify, MUIA_Menuitem_Checked,          MUIV_EveryTime, data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_StyleUnderline,MUIV_TriggerValue);
  2054.          DoMethod(mi_color             ,MUIM_Notify, MUIA_Menuitem_Checked,          TRUE,           data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_Pen,           7);
  2055.          DoMethod(mi_color             ,MUIM_Notify, MUIA_Menuitem_Checked,          FALSE,          data->GUI.TE_EDIT,3,MUIM_Set,MUIA_TextEditor_Pen,           0);
  2056.          DoMethod(data->GUI.RG_PAGE    ,MUIM_Notify,MUIA_Group_ActivePage    ,0             ,MUIV_Notify_Window     ,3,MUIM_Set        ,MUIA_Window_NoMenus,FALSE);
  2057.          DoMethod(data->GUI.RG_PAGE    ,MUIM_Notify,MUIA_Group_ActivePage    ,1             ,MUIV_Notify_Window     ,3,MUIM_Set        ,MUIA_Window_NoMenus,TRUE);
  2058.          DoMethod(data->GUI.RG_PAGE    ,MUIM_Notify,MUIA_Group_ActivePage    ,2             ,MUIV_Notify_Window     ,3,MUIM_Set        ,MUIA_Window_NoMenus,TRUE);
  2059.          DoMethod(data->GUI.ST_SUBJECT ,MUIM_Notify,MUIA_String_Acknowledge  ,MUIV_EveryTime,MUIV_Notify_Window     ,3,MUIM_Set        ,MUIA_Window_ActiveObject,data->GUI.TE_EDIT);
  2060.          DoMethod(data->GUI.BT_ADD     ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_AddFileHook,winnum);
  2061.          DoMethod(data->GUI.BT_ADDPACK ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_AddArchiveHook,winnum);
  2062.          DoMethod(data->GUI.BT_DEL     ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,data->GUI.LV_ATTACH    ,2,MUIM_List_Remove,MUIV_List_Remove_Active);
  2063.          DoMethod(data->GUI.BT_DISPLAY ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,data->GUI.LV_ATTACH    ,3,MUIM_CallHook   ,&WR_DisplayFileHook,winnum);
  2064.          DoMethod(data->GUI.LV_ATTACH  ,MUIM_Notify,MUIA_List_Active         ,MUIV_EveryTime,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_GetFileEntryHook,winnum);
  2065.          DoMethod(data->GUI.RA_ENCODING,MUIM_Notify,MUIA_Radio_Active        ,MUIV_EveryTime,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_PutFileEntryHook,winnum);
  2066.          DoMethod(data->GUI.ST_CTYPE   ,MUIM_Notify,MUIA_String_Contents     ,MUIV_EveryTime,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_PutFileEntryHook,winnum);
  2067.          DoMethod(data->GUI.ST_DESC    ,MUIM_Notify,MUIA_String_Contents     ,MUIV_EveryTime,MUIV_Notify_Application,3,MUIM_CallHook   ,&WR_PutFileEntryHook,winnum);
  2068.          DoMethod(data->GUI.RA_SIGNATURE,MUIM_Notify,MUIA_Radio_Active        ,MUIV_EveryTime,MUIV_Notify_Application,4,MUIM_CallHook   ,&WR_ChangeSignatureHook,MUIV_TriggerValue,winnum);
  2069.          DoMethod(data->GUI.CH_DELSEND ,MUIM_Notify,MUIA_Selected            ,MUIV_EveryTime,mi_delsend             ,3,MUIM_Set        ,MUIA_Menuitem_Checked,MUIV_TriggerValue);
  2070.          DoMethod(data->GUI.CH_RECEIPT ,MUIM_Notify,MUIA_Selected            ,MUIV_EveryTime,mi_receipt             ,3,MUIM_Set        ,MUIA_Menuitem_Checked,MUIV_TriggerValue);
  2071.          DoMethod(data->GUI.CH_DISPNOTI,MUIM_Notify,MUIA_Selected            ,MUIV_EveryTime,mi_dispnoti            ,3,MUIM_Set        ,MUIA_Menuitem_Checked,MUIV_TriggerValue);
  2072.          DoMethod(data->GUI.CH_ADDINFO ,MUIM_Notify,MUIA_Selected            ,MUIV_EveryTime,mi_addinfo             ,3,MUIM_Set        ,MUIA_Menuitem_Checked,MUIV_TriggerValue);
  2073.          DoMethod(mi_autospell         ,MUIM_Notify,MUIA_Menuitem_Checked    ,MUIV_EveryTime,data->GUI.TE_EDIT      ,3,MUIM_Set        ,MUIA_TextEditor_TypeAndSpell,MUIV_TriggerValue);
  2074.          DoMethod(mi_delsend           ,MUIM_Notify,MUIA_Menuitem_Checked    ,MUIV_EveryTime,data->GUI.CH_DELSEND   ,3,MUIM_Set        ,MUIA_Selected,MUIV_TriggerValue);
  2075.          DoMethod(mi_receipt           ,MUIM_Notify,MUIA_Menuitem_Checked    ,MUIV_EveryTime,data->GUI.CH_RECEIPT   ,3,MUIM_Set        ,MUIA_Selected,MUIV_TriggerValue);
  2076.          DoMethod(mi_dispnoti          ,MUIM_Notify,MUIA_Menuitem_Checked    ,MUIV_EveryTime,data->GUI.CH_DISPNOTI  ,3,MUIM_Set        ,MUIA_Selected,MUIV_TriggerValue);
  2077.          DoMethod(mi_addinfo           ,MUIM_Notify,MUIA_Menuitem_Checked    ,MUIV_EveryTime,data->GUI.CH_ADDINFO   ,3,MUIM_Set        ,MUIA_Selected,MUIV_TriggerValue);
  2078.          DoMethod(data->GUI.RA_SECURITY,MUIM_Notify,MUIA_Radio_Active        ,4             ,data->GUI.RA_SIGNATURE ,3,MUIM_Set        ,MUIA_Radio_Active,0);
  2079.          DoMethod(data->GUI.RA_SECURITY,MUIM_Notify,MUIA_Radio_Active        ,4             ,data->GUI.CH_ADDINFO   ,3,MUIM_Set        ,MUIA_Selected,FALSE);
  2080.          for (i = 0; i < 3; i++)
  2081.          {
  2082.             DoMethod(data->GUI.CY_IMPORTANCE,MUIM_Notify,MUIA_Cycle_Active     ,i              ,strip                  ,4,MUIM_SetUData,WMEN_IMPORT0+i,MUIA_Menuitem_Checked,TRUE);
  2083.             DoMethod(data->GUI.WI           ,MUIM_Notify,MUIA_Window_MenuAction,WMEN_IMPORT0+i ,data->GUI.CY_IMPORTANCE,3,MUIM_Set     ,MUIA_Cycle_Active,i);
  2084.          }
  2085.          for (i = 0; i < 4; i++) 
  2086.          {
  2087.             DoMethod(data->GUI.RA_SIGNATURE ,MUIM_Notify,MUIA_Radio_Active     ,i              ,strip                  ,4,MUIM_SetUData,WMEN_SIGN0+i,MUIA_Menuitem_Checked,TRUE);
  2088.             DoMethod(data->GUI.WI           ,MUIM_Notify,MUIA_Window_MenuAction,WMEN_SIGN0+i   ,data->GUI.RA_SIGNATURE ,3,MUIM_Set     ,MUIA_Radio_Active,i);
  2089.          }
  2090.          for (i = 0; i < 5; i++) 
  2091.          {
  2092.            DoMethod(data->GUI.WI           ,MUIM_Notify,MUIA_Window_MenuAction,WMEN_SECUR0+i  ,data->GUI.RA_SECURITY  ,3,MUIM_Set     ,MUIA_Radio_Active,i);
  2093.          }
  2094.          WR_SharedSetup(data, winnum);
  2095.          return data;
  2096.       }
  2097.       free(data);
  2098.    }
  2099.    return NULL;
  2100. }
  2101. ///
  2102. /// WR_NewBounce
  2103. //  Creates a bounce window
  2104. struct WR_ClassData *WR_NewBounce(int winnum)
  2105. {
  2106.    struct WR_ClassData *data;
  2107.  
  2108.    if (data = calloc(1,sizeof(struct WR_ClassData)))
  2109.    {
  2110.       data->GUI.WI = WindowObject,
  2111.          MUIA_Window_Title, GetStr(MSG_WR_BounceWT),
  2112.          MUIA_HelpNode, "WR_W",
  2113.          MUIA_Window_ID, MAKE_ID('W','R','I','B'),
  2114.          WindowContents, VGroup, GroupFrame,
  2115.             MUIA_Background, MUII_GroupBack,
  2116.             Child, ColGroup(2),
  2117.                Child, Label2(GetStr(MSG_WR_BounceTo)),
  2118.                Child, MakeAddressField(&data->GUI.ST_TO, GetStr(MSG_WR_BounceTo), MSG_HELP_WR_ST_TO, ABM_TO, winnum, TRUE),
  2119.             End,
  2120.             Child, ColGroup(4),
  2121.                Child, data->GUI.BT_SEND   = MakeButton(GetStr(MSG_WR_Send)),
  2122.                Child, data->GUI.BT_QUEUE  = MakeButton(GetStr(MSG_WR_ToQueue)),
  2123.                Child, data->GUI.BT_HOLD   = MakeButton(GetStr(MSG_WR_Hold)),
  2124.                Child, data->GUI.BT_CANCEL = MakeButton(GetStr(MSG_Cancel)),
  2125.             End,
  2126.          End,
  2127.       End;
  2128.       if (data->GUI.WI)
  2129.       {
  2130.          DoMethod(G->App, OM_ADDMEMBER, data->GUI.WI);
  2131.          set(data->GUI.ST_TO, MUIA_UserData, data->GUI.BT_SEND);
  2132.          WR_SharedSetup(data, winnum);
  2133.          return data;
  2134.       }
  2135.       free(data);
  2136.    }
  2137.    return NULL;
  2138. }
  2139. ///
  2140.